toISOString()转换印度时区日期显示前一日的原因及修正方案
当处理印度时区(GMT+0530)的日期时,调用toISOString()会得到前一日的结果。例如本地时间Sat Apr 01 2023 00:00:00 GMT+0530,转换后变成2023-03-31T18:30:00.000Z,截取日期部分就得到了错误的2023-03-31。
比如这段代码:
const currentDate = new Date(); const lastMonthStartDate = new Date( currentDate.getFullYear(), currentDate.getMonth() - 1, 1 ); const lastMonthEndDate = new Date( currentDate.getFullYear(), currentDate.getMonth(), 0 ); from = lastMonthStartDate.toISOString().split("T")[0]; to = lastMonthEndDate.toISOString().split("T")[0]; console.log(lastMonthStartDate, lastMonthEndDate); console.log(from,"last month" ,to);
执行后日志显示:
1st log ---->Sat Apr 01 2023 00:00:00 GMT+0530 (India Standard Time) Sun Apr 30 2023 00:00:00 GMT+0530 (India Standard Time)
2nd log----> 2023-03-31 last month 2023-04-29
期望结果却是2023-04-01 last month 2023-04-30。
问题原因
toISOString()方法会将日期转换为UTC时区的字符串。印度时区比UTC快5小时30分,所以本地时间的00:00:00对应UTC的前一天18:30:00,因此ISO字符串显示的日期是UTC的日期,也就是前一日。
解决方案
要获取本地时区的日期格式,需要直接提取本地时间的年、月、日组件,而不是依赖toISOString()。
方法1:手动构造日期字符串
通过getFullYear()、getMonth()、getDate()获取本地日期的各个部分,拼接成yyyy-MM-dd格式:
const currentDate = new Date(); const lastMonthStartDate = new Date( currentDate.getFullYear(), currentDate.getMonth() - 1, 1 ); const lastMonthEndDate = new Date( currentDate.getFullYear(), currentDate.getMonth(), 0 ); // 自定义格式化函数 const formatLocalDate = (date) => { const year = date.getFullYear(); // 月份是0-based,所以加1后补零 const month = String(date.getMonth() + 1).padStart(2, '0'); const day = String(date.getDate()).padStart(2, '0'); return `${year}-${month}-${day}`; }; const from = formatLocalDate(lastMonthStartDate); const to = formatLocalDate(lastMonthEndDate); console.log(lastMonthStartDate, lastMonthEndDate); console.log(from, "last month", to);
方法2:使用Intl.DateTimeFormat API
现代浏览器和Node.js支持Intl.DateTimeFormat,可以直接指定格式和时区(默认本地时区):
const currentDate = new Date(); const lastMonthStartDate = new Date( currentDate.getFullYear(), currentDate.getMonth() - 1, 1 ); const lastMonthEndDate = new Date( currentDate.getFullYear(), currentDate.getMonth(), 0 ); // 利用Intl构造本地日期格式 const formatLocalDate = (date) => { return new Intl.DateTimeFormat('en-CA', { year: 'numeric', month: '2-digit', day: '2-digit' }).format(date); }; const from = formatLocalDate(lastMonthStartDate); const to = formatLocalDate(lastMonthEndDate); console.log(lastMonthStartDate, lastMonthEndDate); console.log(from, "last month", to);
效果
两种方法都能输出期望的结果:
2023-04-01 last month 2023-04-30
内容的提问来源于stack exchange,提问作者Aalbin Tom

