我正在尝试编写一个函数,该函数将接受类似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))
);