解析日期字符串时二月被识别为三月的异常问题求助
解析日期字符串时二月被识别为三月的异常问题求助
问题原因分析
兄弟,你这个问题的坑我之前也踩过!问题出在你初始化localDate的方式和设置日期属性的顺序上——你用new Date()创建了一个当前时间的Date对象,比如如果当前日期是31号的话,就会触发一个很隐蔽的月份溢出问题。
举个具体的场景:假设你运行代码那天是3月31日,代码执行流程会变成这样:
localDate = new Date();—— 此时localDate是当前日期(比如202X-03-31)setFullYear(2023)—— 日期变为2023-03-31setMonth(1)—— 2023年2月没有31天,JavaScript会自动把这个非法日期转换为合法日期:2023-03-03(因为2023年2月只有28天,31-28=3)- 接着你调用
setDate(1)—— 日期就变成了2023-03-01,这就是为什么最终输出是March!
其他月份正常是因为1月、3月、4月等都有足够的天数承接初始日期,不会触发自动溢出转换。
解决方法
给你两个简单靠谱的修复方案:
方案一:直接用Date构造函数初始化
不用先创建当前日期的对象,直接通过new Date(year, month, day, hours, minutes, seconds)一次性传入拆分后的参数,从根源避免溢出问题:
const dateString = '2023-02-01T09:00:00Z' const splitDateTime = new Date(dateString) .toISOString() .split('T'); // ['2023-02-01', '09:00:00'] const dateHalfSplit = splitDateTime[0].split('-'); // ['2023','02','01'] const timeHalfSplit = splitDateTime[1].split(':'); // ['09','00','00'] // 直接用构造函数创建目标日期,注意月份已经减1 const localDate = new Date( parseInt(dateHalfSplit[0]), parseInt(dateHalfSplit[1]) - 1, parseInt(dateHalfSplit[2]), parseInt(timeHalfSplit[0]), parseInt(timeHalfSplit[1]), parseInt(timeHalfSplit[2].split('.')[0]) ); console.info(localDate.toLocaleDateString('en-US', { day: '2-digit', year: 'numeric', month: 'long', hour: 'numeric', minute: '2-digit', hour12: true })); // 输出: February 01, 2023 at 9:00 AM
方案二:调整属性设置顺序
如果一定要用set系列方法,就把设置日期的步骤移到设置月份之前,确保设置月份时的日期是合法的:
const dateString = '2023-02-01T09:00:00Z' const splitDateTime = new Date(dateString) .toISOString() .split('T'); // ['2023-02-01', '09:00:00'] const dateHalfSplit = splitDateTime[0].split('-'); // ['2023','02','01'] const timeHalfSplit = splitDateTime[1].split(':'); // ['09','00','00'] localDate = new Date(); localDate.setFullYear(parseInt(dateHalfSplit[0])); // 先设置日期,确保后续设置月份时日期合法 localDate.setDate(parseInt(dateHalfSplit[2])); // 再设置月份 localDate.setMonth(parseInt(dateHalfSplit[1]) - 1); localDate.setHours(parseInt(timeHalfSplit[0])); localDate.setMinutes(parseInt(timeHalfSplit[1])); localDate.setSeconds(parseInt(timeHalfSplit[2].split('.')[0])); console.info(localDate.toLocaleDateString('en-US', { day: '2-digit', year: 'numeric', month: 'long', hour: 'numeric', minute: '2-digit', hour12: true })); // 输出: February 01, 2023 at 9:00 AM
额外小提醒
其实你处理原始日期字符串的时候,new Date(dateString)已经是一个合法的Date对象了,完全不用转成ISOString再拆分——直接用getUTCFullYear()、getUTCMonth()这些UTC方法提取各个部分,会更简洁也更避免时区坑哦(毕竟你的原始字符串带Z标识是UTC时间)。
备注:内容来源于stack exchange,提问作者Jeremy Trpka
相关产品推荐
相关产品推荐

