又是时间格式化问题,诡异的是只有10月份BUG才出现

举报
Java实用技术@Pandas 发表于 2023/03/31 21:33:11 2023/03/31
【摘要】 十一假期后第一天工作,当大家还沉浸在国庆长假的快乐的时候,我被业务部门急促的电话拉回到现实,生产环境上有页面数据都是空的,而节前还都是好好的。 这就奇了怪了,过了一个国庆,这个bug就闪现出来了?

背景

十一假期后第一天工作,当大家还沉浸在国庆长假的快乐的时候,我被业务部门急促的电话拉回到现实,生产环境上有页面数据都是空的,而节前还都是好好的。

这就奇了怪了,过了一个国庆,这个bug就闪现出来了?

image.png

时间格式化的锅

排查原因

从表象上看是后台没有返回数据,实际是前台的时间传递有问题。

下面这个请求,日期字段date应该是20211011,但是怎么会变成2042呢?

难道过了一个国庆,年份2021就变成了2042吗?

image.png

又是时间格式化问题

下面省略一万秒,前端开发排查后发现了下面的代码:

// 这里省略一万行代码
	let str = ""
	let endDateTime = new Date()
	str += endDateTime.getFullYear()
		+ (endDateTime.getMonth() + 1 < 10 ? '0' + (endDateTime.getMonth() + 1) : endDateTime.getMonth() + 1)
		+ (endDateTime.getDate() < 10 ? '0' + endDateTime.getDate() : endDateTime.getDate())

	let opt = {date: str, 
	          productNo: productNo};

// 这里省略一万头牛

前端大神们看了上面的代码,能一眼看出哪里出问题了吗?

  • 如果你能很看看出问题,说明你的基本功非常扎实。

  • 如果不能一看看出,甚至还要调试一下,说明你基础要加强,你也可能出现类似错误。

这个代码似曾相似,后面会说和时间格式化的第一次邂逅。

解析

endDateTime.getMonth()代码返回的是月份索引(10月份对应9),9+1=10 < 10 是三元表达式条件

三元表达式:
(endDateTime.getMonth() + 1 < 10 ? '0' + (endDateTime.getMonth() + 1) : endDateTime.getMonth() + 1)10月份代码变成了:endDateTime.getMonth() + 1
所以:
str = 2021 + 9 + 1 + 11 = 2042

为什么10月份之前没有问题呢?

因为9月份的时候三元表达式变成了:'0' + (endDateTime.getMonth() + 1)
JS会把结果转成字符串 '09'

不得不佩服开发同学成功地在9月份避开了BUG,导致大家和测试同学都无法在之前测出问题,而10月份问题暴露。

问题解决

开发给的最快解决方案是增加一个操作把年份变成字符串,这样就不存在数字累计导致年月日错误。

// 解决BUG
str += endDateTime.getFullYear() + '' // 这里增加空字符串
		+ (endDateTime.getMonth() + 1 < 10 ? '0' + (endDateTime.getMonth() + 1) : endDateTime.getMonth() + 1)
		+ (endDateTime.getDate() < 10 ? '0' + endDateTime.getDate() : endDateTime.getDate())

当然我们不建议上面的操作,我建议要么写一个健壮的公共的时间格式化工具类,要么引用外部成熟的时间工具类,比如moment.js

// import http://cdn.staticfile.org/moment.js/2.24.0/moment.js
this.date = moment().format('YYYYMMDD');
// 输出:20211011

回忆第一次和时间格式化邂逅

回忆总是让人忧伤。

img

第一次和时间格式化bug的邂逅是2020年元旦。

当很多同事在家喜迎新年的时候,突然业务报问题,说页面上的时间错了。

image.png

时间给了我们一个惊喜,这应该是元旦最难忘的礼物。

还是经过了排查问题–定位问题的过程,最后前端开发媛发现了下面的秘密:

// 先省略一万字码神附体
let mydate = new Date()
let date = mydate.getFullYear() + '-' + 
    (mydate.getMonth() + 1 >= 10 ? mydate.getMonth() + 1 : '0' + mydate.getMonth() + 1)

this.setData({
    mydate: date
})

对于这次bug的解析,欢迎小伙伴们在评论区给出自己的见解。

历史总是惊人的相似,没想到这次又碰到了这个时间格式化bug。

PS:这不是同一个程序员埋的彩蛋。

启示

  1. JavaScript是一个弱类型语言,它不会强制开发者提前指定数据的类型,因此在任何时候,开发人员的疏忽都会导致代码处理走入意想不到的分支,就像上面的代码总是在整数和字符串之间转换。而像Java这样的强类型语言则增加了一些约束,不会随意改变数据类型。除此之外,还要准确使用小括号

  2. 对于新手程序员,不要随便相信网上的代码,多了解每个方法和语法的原理,能用成熟的工具类绝不自己写,要聪明地偷懒。

  3. 人不能两次踏入同一条河流,但是两个程序员可能产生同一种Bug,所以现在读文章的你是否真的学废了时间格式化呢?

我是Pandas,专注Java/JS等编程实用技术分享,公众号Java实用技术手册和B站均有视频解说,欢迎来玩。

如果你觉得这篇文章有用,别忘了点赞+关注,一起进步!

【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。