这篇文章上次修改于 204 天前,可能其部分内容已经发生变化,如有疑问可询问作者。

起因

后端接口返回的时间数据,是一个不带时区的 UTC 字符串。大概长这样:

2023-11-08T08:48:39

翻译到中国时区,就是

2023-11-08 16:48:39

我查找资料后发现,如果想让 new Date()dayjs 默认解析并转换到当前时区,需要在此字符串的末尾加上一个 Z 代表它是 UTC+0 时区,这样前端就能直接识别出服务器返回的时间与对应的时区。

如果是一个带时区的时间,它应该是

2023-11-08T08:48:39Z(ISO 8601 规范,MDN 的推荐)
2023-11-08T08:48:39+0000(前端也能解析)

这两种日期格式交给 new Date() 都是可以直接解析的

MDN 对此的备注:

当用 Date 构造函数(和 Date.parse,它们是等价的)解析日期字符串时,一定要确保输入符合 ISO 8601 格式(YYYY-MM-DDTHH:mm:ss.ssZ),其他格式的解析行为是实现定义的,可能无法在所有浏览器上运行。对 RFC 2822 格式字符串的支持只是惯例。如果要适应许多不同的格式,库可以提供帮助。

仅有日期的字符串(例如 "1970-01-01")被视为 UTC,而日期时间的字符串(例如 "1970-01-01T12:00")被视为本地时间。因此,我们也建议你确保这两种类型的输入格式是一致的。

但后端说这就是一个“UTC 时区”的时间,让我用 UTC 的方式解析,使用 dayjs 可以做到(dayjs.utc()),但需引入对应的 UTC 插件。

对于这个字符串本身,我认为服务端能返回时区是最优解,因为其他项目之前也是这么做的,和客户端对接就没有任何沟通上的成本。

由于这个后端对接的不仅仅是一个 Web 前端,还对接了 iOS App 端,我询问了 App 端的实现过程,则和上面的情况类似,还说这是之前定下的“约定”。

说白了就是后端不返回时区的情况下,你都按照 UTC+0 的方式去解析这个时间字符串。

可我并不知道有这样的约定,我和其他前端对了下,发现他们也并不知道有这样的“约定”,甚至也有直接用 new Date() 解析的。也就是说这个时间字符串的问题在其他项目中也会是一个新 Bug。

后端把 JS 可以处理的方法甩过来之后,搞得我当即气急败坏。仿佛就是我做错了一样,这个问题难道后端就不背锅了么?

分析

考虑到我们团队的前端人数较多,App 开发就只有 2 人,如果要把这个“约定”告诉所有可能参与到项目维护的人来说是不现实的,且容易被疏忽,这不就是埋坑行为么。明明有个很好的官方规范在那,都是人家长期实践过的结果,为什么要自作主张搞一个额外的“约定”出来,增加沟通成本呢?

但现在项目已经完成到了这个程度,这个“错误”也一并存在了许久,就像 Referer 是一个错别字,Referrer 才是正确的一样,一个错误一旦影响程度面大了,后面就只能将错就错了。

如果让后端修改这个时间字符串的格式,他说除了调整当前项目,还需要将相关的几个后端项目一并修改。如果后端不修改,前端目前做好的项目恐怕也需要排查修改一遍,将来不排除还会存在前面提到的“埋坑”问题。

就算后端改了,前端又涉及到 App 端和 Web 端,还需要确认修改是否存在兼容性的问题才行。

前端这边展示过时间的位置确认都是错误的时区,理论上不需要做额外修改。就算按照 UTC 处理,也不存在这个问题:

dayjs.utc("2023-11-08T08:48:39”).unix()
// 169943319

dayjs.utc("2023-11-08T08:48:39Z”).unix()
// 169943319

就是不确定 App 端如果将一个「没带时区」的字符串变成「带时区」的字符串,是否又会变成一个“新的错误”。如果 App 端也是相同的结果,我认为后端应该把这个时间字符串更改为标准的 ISO 8601 规范,在将来的项目维护总是利大于弊的。

作为围观了这样一场风波的你,对此又如何选择呢。