JavaScript日期中的一个错误造成这种偏离的原因是什么



我正在尝试编写一个函数,该函数将接受类似07/2020的字符串,然后返回是否超过三个月。

我已经编写了一个函数isMoreThan3MonthsHence,我确信它是正确的:

const isMoreThan3MonthsHence = ({ utcYear, utcMonth }, 
now = new Date, 
target = new Date(Date.UTC(utcYear, utcMonth)), 
threeMonthsAway = new Date(now.valueOf()).setUTCMonth(now.getUTCMonth() + 3)) => 
(target > threeMonthsAway)
console.log(isMoreThan3MonthsHence({ utcYear: 2020, utcMonth: 7 })) // true (correct!)

当我试图构造一个Date对象来填充isMoreThan3MonthsHence的参数时,问题就出现了。

const validate = (str, 
[localMonth, localYear] = str.split('/'), 
date = new Date(+localYear, (+localMonth)-1)) => 
isMoreThan3MonthsHence({ utcYear: date.getUTCFullYear(), utcMonth: date.getUTCMonth() })
// Note: input is one-based months
console.log(validate('07/2020')) // false (but should be true!)

我认为原因是在validate中新建Date而不指定时区将使用在提供日期生效的本地时区,即BST(UTC+1(。

Wed Jul 01 2020 00:00:00 GMT+0100 (British Summer Time)

这个时间实际上是UTC中6月30日的23点。所以这个月实际上是5,从零开始计算。但我不希望这种行为。我希望这样指定七月实际上意味着UTC中的七月。

我该怎么解决这个问题?

在实例化日期时,似乎混合使用了Date.UTC,而不是。例如,如果您将以下内容用于验证功能:

const validate = (str, 
[month, year] = str.split('/'), 
date = new Date(Date.UTC(+year, (+month)-1))) => 
isMoreThan3MonthsHence({ utcYear: date.getUTCFullYear(), utcMonth: date.getUTCMonth() })
// Note: input is one-based months
console.log(validate('07/2020')) // Now true

它按预期工作:JSFiddle

完全取消Date.UTC的使用将在用户的本地时区执行计算,包括任何适用的夏令时调整。这种可以被视为一种有效的方法,但会导致您所描述的行为。


注意,我已经根据Bergi的反馈重命名了前缀为local的变量。使用Date.UTC意味着您正在传递UTC参数。

除了混合UTC和本地日期外,添加3个月的方式会导致对3月31日等日期的错误响应,其中,仅通过增加月数添加3个月中的日期会导致7月1日的日期。请参阅在JavaScript中为日期添加月份。

因此,如果在3月31日运行,validate('07,2020')将返回false。

要解决此问题,在添加月份时,请检查更新的日期是否仍在该月的同一天,否则它将被滚动,因此将其设置为上个月的最后一天。

function validate(s) {
let testDate = addMonths(new Date(), 3);
let [m, y] = s.split(/D/);
return testDate < new Date(y, m-1);
};
function addMonths(date, months) {
let d = date.getDate();
date.setMonth(date.getMonth() + +months);
// If rolled over to next month, set to last day of previous month
if (date.getDate() != d) {
date.setDate(0);
}
return date;
}
// Sample
console.log('On ' + new Date().toDateString() + ':');
['07/2020', '04/2020'].forEach(
s => console.log(s + ' - ' + validate(s))
);

最新更新