Javascript 日期对象总是休息一天吗?

IT技术 javascript date
2021-02-08 15:24:40

在我的 Java Script 应用程序中,我以如下格式存储日期:

2011-09-24

现在,当我尝试使用上述值创建一个新的 Date 对象(以便我可以以不同的格式检索日期)时,该日期总是在休息一天后返回。见下文:

var doo = new Date("2011-09-24");
console.log(doo);

日志:

Fri Sep 23 2011 20:00:00 GMT-0400 (Eastern Daylight Time)
6个回答

一些疯狂的事情,与JS发生日期对象,将字符串,例如考虑您提供以下日期

注意:以下示例可能会或可能不会休息一天,具体取决于您的时区和当前时间。

new Date("2011-09-24"); // Year-Month-Day
// => Fri Sep 23 2011 17:00:00 GMT-0700 (MST) - ONE DAY OFF.

但是,如果我们将字符串格式重新排列为Month-Day-Year ...

new Date("09-24-2011");
// => Sat Sep 24 2011 00:00:00 GMT-0700 (MST) - CORRECT DATE.

另一个奇怪的

new Date("2011-09-24");
// => Fri Sep 23 2011 17:00:00 GMT-0700 (MST) - ONE DAY OFF AS BEFORE.

new Date("2011/09/24"); // change from "-" to "/".
// => Sat Sep 24 2011 00:00:00 GMT-0700 (MST) - CORRECT DATE.

我们可以在创建新日期时轻松更改日期“2011-09-24”中的连字符

new Date("2011-09-24".replace(/-/g, '\/')); // => "2011/09/24".
// => Sat Sep 24 2011 00:00:00 GMT-0700 (MST) - CORRECT DATE.

如果我们有一个像“2011-09-24T00:00:00”这样的日期字符串怎么办

new Date("2011-09-24T00:00:00");
// => Fri Sep 23 2011 17:00:00 GMT-0700 (MST) - ONE DAY OFF.

现在像以前一样连字符更改正斜杠怎么了?

new Date("2011/09/24T00:00:00");
// => Invalid Date.

我通常必须管理日期格式2011-09-24T00:00:00所以这就是我所做的。

new Date("2011-09-24T00:00:00".replace(/-/g, '\/').replace(/T.+/, ''));
// => Sat Sep 24 2011 00:00:00 GMT-0700 (MST) - CORRECT DATE.

更新

如果您为 Date 构造函数提供单独的参数,您可以获得其他有用的输出,如下所述

注意:参数可以是数字或字符串类型。我将展示具有混合值的示例。

获取给定年份的第一个月和第一天

new Date(2011, 0); // Normal behavior as months in this case are zero based.
// => Sat Jan 01 2011 00:00:00 GMT-0700 (MST)

获取一年的最后一个月和最后一天

new Date((2011 + 1), 0, 0); // The second zero roles back one day into the previous month's last day.
// => Sat Dec 31 2011 00:00:00 GMT-0700 (MST)

数字、字符串参数的示例。请注意,月份是三月,因为再次以零为基础的月份。

new Date(2011, "02"); 
// => Tue Mar 01 2011 00:00:00 GMT-0700 (MST)

如果我们做同样的事情,但一天为零,我们会得到不同的东西。

new Date(2011, "02", 0); // Again the zero roles back from March to the last day of February.
// => Mon Feb 28 2011 00:00:00 GMT-0700 (MST)

向任何年份和月份参数添加零日将获得上个月的最后一天。如果您继续使用负数,您可以继续回滚另一天

new Date(2011, "02", -1);
// => Sun Feb 27 2011 00:00:00 GMT-0700 (MST)
这实际上对我帮助最大。我刚刚在创建新日期时将 .replace(/-/g, '\/').replace(/T.+/, '') 添加到数据的末尾。超级简单!
2021-03-16 15:24:40
.replace() 调用在今晚的紧急情况下真的很有帮助。
2021-03-17 15:24:40
所有这些都是由于底层 Date.parse() 尝试遵循 ISO 8601 的行为。当日期字符串遵循 yyyy-mm-dd 格式时,它被假定为带有隐式 UTC 00:00 的 ISO 8601。当字符串偏离格式(例如 mm-dd-yyyy 或斜杠而不是连字符)时,它会根据 RFC 2822 使用本地时间,当时区不存在时,它会回退到更宽松的解析器。诚然,这对普通人来说都是相当神秘的。
2021-04-03 15:24:40
哇 - javascript 非常不一致。
2021-04-07 15:24:40
但对我们来说不是!这个评论是一个很好的补充。我不知道它为什么这样做,只是它做到了。
2021-04-07 15:24:40

请注意,东部夏令时间是-4 hours,您返回日期的小时数是20

20h + 4h = 24h

这是 2011-09-24 的午夜。日期以 UTC (GMT)解析,因为您提供了一个没有任何时区指示符的仅日期字符串。如果您提供了一个没有指示符的日期/时间字符串 ( new Date("2011-09-24T00:00:00")),它将在您的本地时区中进行解析。(历史上一直存在不一致,尤其是因为规范更改了不止一次,但现代浏览器应该没问题;或者您始终可以包含时区指示器。)

您得到了正确的日期,只是您从未指定正确的时区。

如果您需要访问日期值,您可以使用getUTCDate()任何其他getUTC*()功能

var d,
  days;
d = new Date('2011-09-24');
days = ['Sun', 'Mon', 'Tues', 'Wed', 'Thurs', 'Fri', 'Sat'];
console.log(days[d.getUTCDay()]);

从字符串中将其创建为 UTC 将是我想要做的,因此我问“你如何“指定正确的时区”?关于您所说的“您只是从未指定正确的时区。”。如果我这样做,new Date('2012-01-01 GMT')它仍然会应用偏移量,因为它将它转换为用户的本地日期时间。
2021-03-21 15:24:40
@AaronLS,如果您被迫使用这些get*方法并需要它返回正确的日期/时间,包括未知时区偏移,只需添加未知时区偏移:d = new Date('2013-01-08 GMT'); d.setMinutes(d.getMinutes() + d.getTimezoneOffset());这会将日期标准化为用户的语言环境,以便.get*方法返回期望值。.getUTC*随后的方法将是不正确的,所以要小心。
2021-03-29 15:24:40
这些评论中的许多都做出了一个巨大的假设,即使用了我们创建的日期。如果像我一样,您从其他来源获取日期,例如使用 dd-mmm-yy 格式的 oracle,该怎么办。我也不知道他们将来是否打算更改此格式,因为他们的应用程序很旧,如果手动处理可能会破坏我的程序,因此我需要一个通用转换器。如果没有在解析期间指定本地时区的机制,这种 UTC 日期假设同样糟糕。对我来说,问题仍然存在。我如何确保在解析过程中日期没有改变
2021-03-29 15:24:40
@AaronLS,EDT夏令时(也称为夏令时)EST是一月份适用的时区。
2021-04-08 15:24:40
你如何“指定正确的时区”?日期构造函数始终将日期字符串解释为 UTC,但随后会针对时区进行调整。我什至可以做`new Date('2012-01-02 EDT') 并且由于应用夏令时的偏移量仍然将它移回前一天,这是没有意义的,因为如果我告诉你那是日期EDT 的当前本地时区,然后不要对其应用额外的偏移量。我告诉它时区是 EDT,但它仍然应用额外的偏移量将其移回一天。
2021-04-09 15:24:40

将日期标准化并消除不需要的偏移(此处测试:https : //jsfiddle.net/7xp1xL5m/):

var doo = new Date("2011-09-24");
console.log(  new Date( doo.getTime() + Math.abs(doo.getTimezoneOffset()*60000) )  );
// Output: Sat Sep 24 2011 00:00:00 GMT-0400 (Eastern Daylight Time)

这也实现了相同的功能并归功于@tpartee(此处测试:https : //jsfiddle.net/7xp1xL5m/1/ ):

var doo = new Date("2011-09-24");
console.log( new Date( doo.getTime() - doo.getTimezoneOffset() * -60000 )  );
@AaronLS 您在正确的轨道上,但逻辑略有错误。为了补偿 TZ 偏移,正确的逻辑是: console.log( new Date( doo.getTime() - doo.getTimezoneOffset() * -60000 ) ); - 偏移量的符号很重要,不能绝对化,但您还需要反符号进行校正,因此我们将偏移量乘以 -60000 以应用反符号。
2021-03-26 15:24:40
我做了类似的事情: doo.setMinutes(doo.getMinutes() + doo.getTimezoneOffset())
2021-03-29 15:24:40
@ErikAGriffin 您是否处于正时区,即 GMT+0X00 而不是 GMT-0X00 ?
2021-04-01 15:24:40
这对我有用,除了我必须减去 timeZoneOffset,而不是添加它
2021-04-06 15:24:40
这对我来说是这样做的 - 我必须处理来自 API 的日期,然后对它们进行排序/比较,因此只需添加时区偏移量效果最佳。
2021-04-07 15:24:40

我认为这与时区调整有关。您创建的日期是 GMT,默认时间是午夜,但您的时区是 EDT,因此减去 4 小时。试试这个来验证:

var doo = new Date("2011-09-25 EDT");
我不知道幕后发生了什么,但它完美地工作。
2021-03-14 15:24:40
我会说这是最简单的答案和更少的代码重新格式化。
2021-03-25 15:24:40
谢谢,我认为对我来说最好的方法。
2021-03-26 15:24:40
这个有帮助。它是这样工作的:$scope.dat = new Date(datestring + 'EDT')。请注意 EDT 和 EST 之间的区别:链接
2021-03-30 15:24:40
这是这里最好的答案。+100 万用于使用内置时区本地化字符串而不是以编程方式转换。
2021-04-03 15:24:40

如果要获取本地时区中某个日期的 0 小时,请将各个日期部分传递给Date构造函数。

new Date(2011,08,24); // month value is 0 based, others are 1 based.