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


238

在我的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)

11
Javascript的Date类不表示日期,而是表示时间戳(与Java相同)。为了使其成为日期,它使用了时区,这就是造成问题的原因。它与GMT / UTC时区(2011年9月24日,将其解析00:00 UTC),然后用不同的时区的4小时(2011年9月23日,其输出20:00 GMT-0400)。
Codo

2
我得到“无效日期”。将'-'字符替换为'/'字符,然后重试。或将日期分成几部分,然后分别设置各个组成部分(如果这样做,则从月份中减去1)。
RobG 2011年

@Codo-是的,很好的答复。ECMA-262 15.9.1.15适用。OP应使用“ 2011-09-24T20:00:00-04:00”或类似名称。
RobG 2011年

1
我发现格式“ Sep 24 2011”将返回正确的日期。看到这里的解释:stackoverflow.com/questions/2587345/javascript-date-parse
christurnerio 2013年

Answers:


98

请注意,东部夏令时间为-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()]);

24
您如何“指定正确的时区”?日期构造函数始终将日期字符串解释为UTC,但会针对时区进行调整。我什至可以执行`new Date('2012-01-02 EDT')并将其移回前一天,这是由于应用了夏令时的偏移量,这没有任何意义,因为如果我告诉您这是按照EDT的当前本地时区,则不要对其应用额外的偏移量。我告诉它时区为EDT,但它仍会应用一个额外的偏移量,将其移回一天。
AaronLS

1
@AaronLS EDT夏令时(也称为夏令时)EST是一月份的时区。
zzzzBov

1
我想从字符串中以UTC形式创建它,因此为什么我问“您如何“指定正确的时区”?” 关于您所说的“您从未指定正确的时区”。如果我这样做,new Date('2012-01-01 GMT')它仍然会应用偏移量,因为它将其转换为用户的本地日期时间。
AaronLS

7
@AaronLS,如果您被迫使用这些get*方法并需要它返回正确的日期/时间(包括未知的时区偏移量),只需添加未知的时区偏移量即可:d = new Date('2013-01-08 GMT'); d.setMinutes(d.getMinutes() + d.getTimezoneOffset());这会将日期标准化为用户的语言环境,以便.get*方法返回期望值。该.getUTC*方法将不正确,因此请小心。
zzzzBov

1
在定义行为以提供引用和将其用作转义符(实现者未能正确实现某些东西)之间存在区别。而且这相同的表示,如果数据不排队的期望。
持不同政见者愤怒

252

一些疯狂的事情,与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构造函数提供单独的参数,则可以获取其他有用的输出,如下所述

注意:参数的类型可以为Number或String。我将显示带有混合值的示例。

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

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)

12
这实际上帮了我最大的忙。当我确定新日期时,我只是在数据末尾添加了.replace(/-/ g,'\ /')。replace(/ T。+ /,'')。超级容易!
Devin Prejean

64
哇-JavaScript非常不一致。
psparrow '16

2
今天晚上,.replace()调用确实有所帮助。
停用

2
是的,我已经测试了这一切,这真的很奇怪。
chintan adatiya

26
所有这些都是由于基础Date.parse()试图遵循ISO 8601的行为所致。当日期字符串遵循yyyy-mm-dd格式时,假定它是具有隐式UTC 00:00的ISO 8601。当字符串偏离格式(例如,mm-dd-yyyy或斜杠而不是连字符)时,它会退回到根据RFC 2822使用松散的解析器,该解析器在缺少时区时使用本地时间。诚然,这对于普通人来说都是相当神秘的。
Mizstik '16

71

为了标准化日期并消除不必要的偏移量(在此处测试: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 )  );

这为我做到了-我必须使用API​​中的日期,然后对它们进行排序/比较,因此简单地添加时区偏移效果最佳。
chakeda '16

这对我有用,除了我不得不减去timeZoneOffset而不是添加它
ErikAGriffin

@ErikAGriffin您是否处于正时区,即IE GMT + 0X00而不是GMT-0X00?
AaronLS '16

我做了类似的事情:doo.setMinutes(doo.getMinutes() + doo.getTimezoneOffset())
Dissident Rage

2
@AaronLS您的方向正确,但逻辑略有错误。为了补偿TZ偏移,正确的逻辑是:console.log(new Date(doo.getTime()-doo.getTimezoneOffset()* -60000))); -偏移量的符号很重要,不能绝对消除,但您还需要反符号进行校正,因此我们将偏移量乘以-60000即可应用反符号。
tpartee

28

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

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

26

只是想添加一点,显然在字符串末尾添加一个空格将使用UTC进行创建。

new Date("2016-07-06")
> Tue Jul 05 2016 17:00:00 GMT-0700 (Pacific Daylight Time)

new Date("2016-07-06 ")
> Wed Jul 06 2016 00:00:00 GMT-0700 (Pacific Daylight Time)

编辑:这不是推荐的解决方案,只是一个替代答案。请不要使用此方法,因为尚不清楚发生了什么。有人可以通过多种方式将其重构,从而导致错误。


对于末尾带有空格的示例,控制台返回“ Invalid Date = $ 2”
Brian Risk

1
效果很好!新的Date(data.Date +“”).toLocaleDateString(“ en-US”)
Nakres

公平地说,这只是一个替代答案,而不是推荐的解决方案。
凯尔·施拉德

25

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

var doo = new Date("2011-09-25 EDT");

3
这是最好的答案。+1百万用于使用内置时区本地化字符串而不是通过编程方式进行转换。
blearn

2
这有帮助。它的工作方式如下:$ scope.dat = new Date(datestring +'EDT')。不过请注意EDT和EST之间的区别:链接
Guoweihui Guo

我不知道幕后发生了什么,但是效果很好。
the_haystacker

我想说这是最简单的答案,而且代码重新格式化更少。
迈克尔

谢谢,我认为是最好的方式。
詹德森·君士坦丁堡

11

您的问题专门与时区有关。注意部分GMT-0400-也就是说,您比格林尼治标准时间晚4小时。如果您将4小时添加到显示的日期/时间中,您将获得确切的2011/09/24午夜。使用toUTCString()方法代替获取GMT字符串:

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

6

这可能不是一个很好的答案,但是我只想分享我在此问题上的经验。

我的应用程序在全球范围内使用utc日期,格式为“ YYYY-MM-DD”,而我使用的datepicker插件仅接受js日期,因此我很难同时考虑utc和js。因此,当我想将“ YYYY-MM-DD”格式的日期传递给我的日期选择器时,我首先要使用moment.js或任何您喜欢的格式将其转换为“ MM / DD / YYYY”格式,并且日期选择器上显示的日期现在是正确。举个例子

var d = new Date('2011-09-24'); // d will be 'Fri Sep 23 2011 20:00:00 GMT-0400 (EDT)' for my lacale
var d1 = new Date('09/24/2011'); // d1 will be 'Sat Sep 24 2011 00:00:00 GMT-0400 (EDT)' for my lacale

显然D1是我想要的。希望这对某些人有帮助。


像您一样切换格式,对我来说也一样。太奇怪了。
jAC

5

通过我的这个循环,zzzBov的答案+1。这是使用UTC方法对我有用的日期的完整转换:

//myMeeting.MeetingDate = '2015-01-30T00:00:00'

var myDate = new Date(myMeeting.MeetingDate);
//convert to JavaScript date format
//returns date of 'Thu Jan 29 2015 19:00:00 GMT-0500 (Eastern Standard Time)' <-- One Day Off!

myDate = new Date(myDate.getUTCFullYear(), myDate.getUTCMonth(), myDate.getUTCDate());
//returns date of 'Fri Jan 30 2015 00:00:00 GMT-0500 (Eastern Standard Time)' <-- Correct Date!

4

意思是2011-09-24 00:00:00 GMT,由于您在GMT -4,所以会是20:00前一天。

就我个人而言,我得到了2011-09-24 02:00:00,因为我住在GMT +2


3

尽管在OP中,时区为EDT,但不能保证执行脚本的用户将在EDT时区,因此硬编码偏移量不一定有效。我找到的解决方案拆分日期字符串,并在Date构造函数中使用单独的值。

var dateString = "2011-09-24";
var dateParts = dateString.split("-");
var date = new Date(dateParts[0], dateParts[1] - 1, dateParts[2]);

请注意,您还必须考虑另一段JS异常:月份从零开始。


2

我的客户使用大西洋标准时间时,我遇到了这个确切的问题。客户端检索到的日期值为“ 2018-11-23”,并且代码将其传递到new Date("2018-11-23")客户端的输出中时为前一天。我创建了一个效用函数,如片段中所示,它对日期进行了归一化处理,从而为客户提供了预期的日期。

date.setMinutes(date.getMinutes() + date.getTimezoneOffset());

var normalizeDate = function(date) {
  date.setMinutes(date.getMinutes() + date.getTimezoneOffset());
  return date;
};

var date = new Date("2018-11-23");

document.getElementById("default").textContent = date;
document.getElementById("normalized").textContent = normalizeDate(date);
<h2>Calling new Date("2018-11-23")</h2>
<div>
  <label><b>Default</b> : </label>
  <span id="default"></span>
</div>
<hr>
<div>
  <label><b>Normalized</b> : </label>
  <span id="normalized"></span>
</div>


2

如果您只是想确保日期的各个部分保持一致以进行显示,那么即使我更改了时区,这也可以正常工作:

var doo = new Date("2011-09-24 00:00:00")

只需在其中添加零。

在我的代码中,我这样做:

let dateForDisplayToUser = 
  new Date( `${YYYYMMDDdateStringSeparatedByHyphensFromAPI} 00:00:00` )
  .toLocaleDateString( 
    'en-GB', 
    { day: 'numeric', month: 'short', year: 'numeric' }
  )

然后,我在计算机上切换了时区,并且日期与从API获取的yyyy-mm-dd日期字符串相同。

但是我错过了什么吗?

*至少在镀铬中。这在Safari中不起作用!截至撰写本文时


当您这样做时.toISOString(),它可以返回1天。
vivek_23 '19

new Date('2019/11/18 05:30:00').toISOString();为我工作
vivek_23,2014年

1

无需使用更多转换方法即可解决此问题的最佳方法,

 var mydate='2016,3,3';
 var utcDate = Date.parse(mydate);
 console.log(" You're getting back are 20.  20h + 4h = 24h :: "+utcDate);

现在,只需在您的日期中添加GMT即可,也可以添加它。

 var  mydateNew='2016,3,3'+ 'GMT';
 var utcDateNew = Date.parse(mydateNew);
 console.log("the right time that you want:"+utcDateNew)

直播:https//jsfiddle.net/gajender/2kop9vrk/1/


1

我遇到了这样的问题。但是我的问题是从数据库获取日期时出现了偏移。

它以UTC格式存储在数据库中。

2019-03-29 19:00:00.0000000 +00:00

因此,当我从数据库获取日期并检查日期时,它会添加偏移量并发送回javascript。

在此处输入图片说明

它正在添加+05:00,因为这是我的服务器时区。我的客户所在的时区是+07:00。

2019-03-28T19:00:00 + 05:00 //这是我在JavaScript中得到的东西。

所以这是我的解决方案,我该如何处理。

var dates = price.deliveryDate.split(/-|T|:/);
var expDate = new Date(dates[0], dates[1] - 1, dates[2], dates[3], dates[4]);
var expirationDate = new Date(expDate);

因此,当日期来自服务器并具有服务器偏移量时,我拆分日期并删除服务器偏移量,然后转换为日期。它解决了我的问题。



0

您正在使用ISO日期字符串格式,根据此页面格式会导致使用UTC时区构造日期:

注意:由于浏览器的差异和不一致,强烈建议不要使用Date构造函数(和Date.parse,它们等效)来解析日期字符串。仅按惯例,对RFC 2822格式字符串的支持。对ISO 8601格式的支持有所不同,因为仅日期字符串(例如“ 1970-01-01”)被视为UTC,而不是本地。

如果您以其他方式设置文本格式,例如"Jan 01 1970",则(至少在我的机器上)它使用您的本地时区。


0

尝试将我的2美分添加到该线程中(详细说明@ paul-wintz答案)。

在我看来,当Date构造函数接收到与ISO 8601格式的第一部分(日期部分)匹配的字符串时,它将在UTC时区中以0时间进行精确的日期转换。当该日期转换为本地时间时,如果午夜UTC是本地时区中的较早日期,则可能会发生日期转换。

new Date('2020-05-07')
Wed May 06 2020 20:00:00 GMT-0400 (Eastern Daylight Time)

如果日期字符串采用任何其他“更宽松”的格式(使用“ /”或日期/月份未填充零),则它将在本地时区创建日期,因此不会出现日期转换问题。

new Date('2020/05/07')
Thu May 07 2020 00:00:00 GMT-0400 (Eastern Daylight Time)
new Date('2020-5-07')
Thu May 07 2020 00:00:00 GMT-0400 (Eastern Daylight Time)
new Date('2020-5-7')
Thu May 07 2020 00:00:00 GMT-0400 (Eastern Daylight Time)
new Date('2020-05-7')
Thu May 07 2020 00:00:00 GMT-0400 (Eastern Daylight Time)

因此,如上所述,一种快速解决方案是在ISO格式的“仅日期”字符串中将“-”替换为“ /”。

new Date('2020-05-07'.replace('-','/'))
Thu May 07 2020 00:00:00 GMT-0400 (Eastern Daylight Time)

0

yyyy-mm-dd以MySql Date格式存储时,您必须执行以下操作:

const newDate = new Date( yourDate.getTime() + Math.abs(yourDate.getTimezoneOffset()*60000) );
console.log(newDate.toJSON().slice(0, 10)); // yyyy-mm-dd

-1

您的日志输出GMT,因此您想指定时区:

var doo = new Date("2011-09-24 EST");

3
这个问题已经有很多答案。如果您仍然想回答该问题,则应提及其他答案未回答的新内容。最佳答案已经详细解释了时区问题。
加尔文·戈弗雷


谁在乎他的解释是否更深入……他的代码仍然与我的不同。我的要简单得多。是的,石蜘蛛是正确的。我的错。
bmacx7

-3

没关系,没注意到格林尼治标准时间-0400,这导致日期是昨天

您可以尝试将默认的“时间”设置为12:00:00


是的,我的回答有点快,对此感到抱歉。修改了我的答案。
ChrisH 2011年

-3

以下为我工作-

    var doo = new Date("2011-09-24").format("m/d/yyyy");

只要您不摆弄时区,它仍然无法正常工作。
Gar
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.