记一次线上bug,Safari 浏览器new Date获取时间戳为NaN

1,956 阅读3分钟

「这是我参与2022首次更文挑战的第1天,活动详情查看:2022首次更文挑战

场景

前端有个列表展示,产品要根据日期倒叙展示。上线一天后,突然反馈,苹果浏览器排序无效。 what 谷歌浏览没问题啊,借个苹果电脑看看,天啊,排序真的无效。 大概代码如下

const list = ['2021-1-12', '2021-1-13', '2021-1-14', '2021-1-15'];
list.sort((a, b) => new Date(b).getTime() - new Date(a).getTime());

这段代码没问题好说的,普通的在没法普通了。

排查问题

先看看接口返回数据的格式有没有问题,没问题,而且谷歌浏览器没问题。

可能是Array.sort 问题

测试代码

const list=[1,2,3,4,5,6];
list.sort((a,b)=>b-a);
console.log(list); # [6,5,4,3,2,1]

chrome 和Safari 都问题, sort方法没问题。

可能是new Date 问题

测试代码

console.log(new Date('2021-1-12'));
console.log(new Date('2021-1-12').getTime());

chrome下一切正常。safari下竟然是 Invalid DateNaN 那问题就很明显了。safari 浏览器new Date()有问题,仔细观察这个时间字符串后发现,和我们常用略微有点差异 ,我们平时用的是YYYY-MM-DD,这个后台返回的是YYYY-M-DD,当月份是个位的时候前面没有补0.

上完成测试代码

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>

<body>
</body>
<script src="https://cdn.bootcdn.net/ajax/libs/dayjs/1.10.7/dayjs.min.js"></script>
<script>
  console.log(new Date('2021-1-12'));
  console.log(new Date('2021-1-12').getTime());

  const list = ['2021-1-12', '2021-1-13', '2021-1-14', '2021-1-15'];
  list.sort((a, b) => new Date(b).getTime() - new Date(a).getTime());
  console.log(list);
  // dayjs
  const day = dayjs('2021-1-12').format('YYYY-MM-DD');
  console.log(day);
  console.log(new Date(day));


</script>

</html>

chrome下一切正常。来看看safari下

微信图片_20220119230720.jpg 通过上图我们能看出来,在使用dayjs格式化日期后就可以了。到这个地方解决问题的办法就有很多了,项目中可以使用dayjs来做日期格式化,也可以自己用判断字符串然后月份补0

为啥会出现这个问题

MDN上关于Date的介绍

Date

创建一个 JavaScript Date 实例,该实例呈现时间中的某个时刻。Date 对象则基于 Unix Time Stamp,即自1970年1月1日(UTC)起经过的毫秒数。

时间戳字符串

dateString 表示日期的字符串值。该字符串应该能被 Date.parse() 正确方法识别(即符合 IETF-compliant RFC 2822 timestamps 或 version of ISO8601)。

  • 注意:  由于浏览器之间的差异与不一致性,强烈不推荐使用Date构造函数来解析日期字符串 (或使用与其等价的Date.parse)。对 RFC 2822 格式的日期仅有约定俗成的支持。 对 ISO 8601 格式的支持中,仅有日期的串 (例如 "1970-01-01") 会被处理为 UTC 而不是本地时间,与其他格式的串的处理不同。

上文介绍到了Date.parse我们在safari下测试使用试试

Date.parse('2021-1-12'); # NaN 

好吧,这个不行。 ECMAScript  规范规定:如果一个字符串不符合标准格式,则函数可以使用任何由引擎决定的策略或解析算法。 Date.parse()  对于因包含有无效元素而无法识别的 ISO 格式字符串或者日期应该返回 NaN 。

但是, 在如 ECMA-262 规范中定义的情况,如果因为无效值而导致日期字符串不能被识别为 ISO 格式时,根据浏览器和给定的值不同,返回值可以是,也可以不是 NaN

总结

此次问题的出现是由于后台格式化日期字符串,没有按照YYYY-MM-DD来格式化,前端处理的时候没有考虑浏览器差异。和后台达成共识,以后日期要么严格按照YYYY-MM-DD,要么就转成时间戳。至于有人问,为啥这么简单的排序后端不做。鬼知道