设置为2014年12月31日的新Date()改为说12月1日


80

我正在尝试将字符串转换为Date对象,并且它适用于所有日期,除了12月31日(按对象说12月1日而不是31日)之外。我不知道为什么。这是我的JavaScript代码:

var dt = new Date();
dt.setDate("31");
dt.setMonth("11");
dt.setFullYear("2014");

但我的变量值为:

Mon Dec 01 2014 11:48:08 GMT+0100 (Paris, Madrid)

如果我在其他任何日期都这样做,则我的对象将返回适当的值。你知道我做错了什么吗?


7
您是将整数传递给setMonth等,而不是字符串。
funkybro 2014年

15
您可以Date直接使用构造函数的参数:new Date(2014, 11, 31)
pomeh 2014年

9
顺便说一句 不是11月11日?
jnovacho 2014年


5
@JuhaUntinen不,日期不正确,因为现在的月份只有30天。
李斯特先生2014年

Answers:


85

setMonth 应该在 setDate:(少于31天的月份不安全

var dt = new Date();
dt.setFullYear(2014);
dt.setMonth(11);
dt.setDate(31);

并且setMonth的第二个参数也可以用来设置日期。

var dt = new Date();
dt.setFullYear(2014);
dt.setMonth(11, 31);


如果没有为构造函数提供任何参数,它将根据系统设置使用当前日期和时间

因此,单独使用setMonthsetDate仍会导致意外结果。

如果设置的值大于其逻辑范围,则该值将自动调整为相邻的值

例如,如果今天是2014-09-30,则

var dt = new Date();
dt.setFullYear(2014); /* Sep 30 2014 */
dt.setMonth(1);       /* Mar 02 2014, see, here the auto adjustment occurs! */
dt.setDate(28);       /* Mar 28 2014 */

为避免这种情况,请直接使用构造函数设置值。

var dt = new Date(2014, 11, 31);

1
我确实发现了它,但是对我来说真的没有意义
user2859409 2014年

15
@ user2859409,这可能是因为如果您不首先设置月份,则需要使用当前月份,然后有时可能会
套用

3
我会毫不犹豫地建议将第一段代码用于少于31天的月份。例如,如果您要将日期设置为9月15日,但今天是8月31日,则该日期将回溯到下个月,并且您将以10月15日结束。+1为第二个代码段:即更好的方法。我什至不知道setMonth存在的2参数形式。
卢克·伍德沃德

10
请注意,将日期设置为前一天也可能是错误的。但是,在这种情况下不是。如果是10月31日,则setMonth(10)将日期设置为11月31日,该日期将换行为12月1日。setDate(31)然后返回12月31日。因此,请始终使用2个参数setMonth()。
Florian F

1
+1,但我想强调指出,两个月的选项是首选,以防止出现副作用。
布莱恩(Brian)

120

问题是,当您将日期设置为第一天时,您仍处于当前月份,因此是9月。九月只有30天,因此:

var dt = new Date(); /* today */
dt.setDate("31"); /* 1st Oct 2014 as should be by spec */
dt.setMonth("11"); /* 1st Dec 2014 */
dt.setFullYear("2014"); /* 1st Dec 2014 */

22
+
1-

19
这是从来没有在正确的时间设定一个日期一个组成部分,因为有故障的情况下与第一天,并与第一个月,可能与年先2/29。您必须同时设置所有三个字段。
Jim Garrison 2014年

5
+1,应该是可以接受的答案,因为它说明了为什么要先设置月份。这是一个非常JavaScript的WTF
Danubian Sailor

2
其他语言应该相似,因此不能是“ javascript WTF”。
Raidri在2014年

为什么设置了错误的日期后Date对象没有抛出?
jww

23

因为你要做的第一件事是

dt.setDate(31)

这会将当前日期设置为31。当前月份是9月,该日期有30天,因此将其环绕起来。

如果要在此之后打印日期,则将显示10月1日。


12
有趣的是,这只是因为他在30天的一个月内尝试过才弹出。一个月后,它似乎可以正常工作。
彼得·雷默斯

13

假设您打算同时设置年,月和日,则可以使用较长的日期构造函数

新日期(年,月,日,小时,分钟,秒,毫秒);

[...]

如果至少提供了两个参数,则将缺少的参数设置为1(如果缺少日期)或将其他所有参数设置为0。

所以你会写:

var dt = new Date(2014, 11, 31);

如已经确定的那样,一次设置日期的一部分会导致溢出:

var dt = new Date(2012, 1, 29); // Feb 29 2012
dt.setFullYear(2014);           // Mar 01 2014 instead of Feb 28 2014

此外,将日期设置为月前仍然会导致意外溢出(建议更改方法顺序的答案不正确):

var dt = new Date(2014, 0, 31); // Jan 31 2014
dt.setFullYear(2014);           // Jan 31 2014
dt.setMonth(1);                 // Mar 03 2014 instead of Feb 28 2014
dt.setDate(1);                  // Mar 01 2014

我喜欢这个答案,因为它在顶部为您提供了正确的解决方案,然后解释了为什么破碎的解决方案不起作用...
Kip

7

已经充分解释了该行为的原因以及如何避免该行为。

但是代码中真正的错误是您不应该使用默认的构造函数:new Date()。您的代码将导致当前日期为12月13日。我怀疑这就是你想要的。您应该使用以年,月和日为参数的Date构造函数。


1
我想是要对接受的答案发表评论?
Danubian Sailor'Sep

并不是的。这是对“我错了吗?”这个问题的答案。
Florian F

-1

答案清楚地表明,设置日期的正确顺序是:

  • setFullYear()
  • setMonth()
  • 设置日期()

我只想指出,由于leap年2月29日,因此将年份定为第一年也很重要。


1
否。该订单不能保证正确设置日期。请参阅下面的评论,这些评论是公认的且投票最多的答案。
Salman 2014年

1
如果您的开始日期是31日,并且您将其设置为更少(例如30天)天的月份,那么您将在下个月结束。因此,这还不够。为了安全起见,在设置月份之前,应将日期设置为不大于28的日期。最后,将日期再次设置为其最终值(如果较高)。
巴特2014年

-3
var dt = new Date();
dt.setFullYear(2014);
dt.setMonth(11);
dt.setDate(31);

将值传递为整数而不是字符串。它将返回正确的值。


更新-上面的描述是不正确的..主要问题是您需要按正确的顺序放置这三行。


不,不是这样,这是我在chrome控制台中进行的测试:var dt = new Date(); 未定义dt.setDate(31); 1412157761255 dt.setMonth(11); 1417431761255 dt.setFullYear(2014); 1417431761255 dt 2014年12月1日星期一12:02:41 GMT + 0100(巴黎,马德里)
user2859409 2014年

6
它与参数的类型无关,与序列无关。您提到的顺序好像是次要的……
dee-

1
在该代码有效的同时,您给出了错误的解释,为什么。
Danubian Sailor'Sep
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.