new Date () встановлено на 31 грудня 2014 року, а замість цього - 1 грудня


80

Я намагаюся перетворити рядок на об'єкт Date, і це працює всі дні, крім 31 грудня, де за об'єктом пише 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

15
Ви можете використовувати параметри Dateконструктора безпосередньо:new Date(2014, 11, 31)
pomeh

9
до речі. не 11 листопада?
jnovacho


5
@JuhaUntinen Ні, дата змішана, оскільки місяць зараз має лише 30 днів.
Містер Лістер,

Відповіді:


85

setMonth слід до setDate: ( не безпечно протягом місяців менше 31 дня )

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

А setMonth«s другий параметр також може бути використаний для установки дати.

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


Якщо для конструктора не надано аргументів, він використовуватиме поточну дату та час відповідно до системних налаштувань.

Отже, використання setMonthта setDateокремо все одно призведе до несподіваного результату.

Якщо набір значень перевищує їх логічний діапазон , значення буде автоматично налаштовано на сусіднє значення .

Наприклад, якщо сьогодні є 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

15
@ user2859409 це, мабуть, тому, що якщо ви не встановите місяць спочатку, це займе поточний місяць, а потім може іноді перейти в наступний місяць (відповідно до відповіді Якуба нижче)
fbstj,

3
Я б вагався рекомендувати цей перший блок коду на місяці, менше ніж 31 день. Якщо, наприклад, ви хочете встановити дату 15 вересня, але це сьогодні 31 серпня, дата перенесеться на наступний місяць, і ви закінчите 15 жовтня. +1 для другого блоку коду: це кращий спосіб піти. Я навіть не знав, як існує 2 аргументи setMonth.
Luke Woodward

10
Зверніть увагу, що встановлення місяця перед днем ​​також може бути помилковим. Однак не в цьому випадку. Якщо це 31 жовтня, тоді setMonth (10) встановить дату 31 листопада, яка перенесеться до 1 грудня. SetDate (31), а потім результат 31 грудня. Отже, завжди використовуйте 2-аргумент setMonth ().
Florian F

1
+1, але я б підкреслив, що двомісячний варіант є кращим для запобігання побічним ефектам.
Брайан

120

Справа в тому, що коли ви встановлюєте день першим, ви все ще перебуваєте в поточному місяці, отже, вересень. У вересні лише 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 - Це така помилка, яка буде лежати в стані спокою весь серпень, а потім вкусить вас за зад, прийде вересень;)
Niet the Dark Absol

19
НІКОЛИ не право встановлювати дату по одному компоненту за раз, оскільки трапляються випадки відмов із першим днем та першим місяцем, а можливо , і першим роком 2/29. Ви повинні встановити всі три поля одночасно.
Джим Гаррісон,

5
+1, і це має бути прийнятою відповіддю, оскільки це пояснює, ЧОМУ спочатку слід встановити місяць. Це дуже javascript WTF
Дунайський моряк

2
Має бути подібним в інших мовах, тому не "javascript WTF".
Raidri підтримує Моніку

Чому об’єкт Date не викидає, коли встановлено неправильну дату?
jww

23

Це тому, що перше, що ти робиш, це

dt.setDate(31)

Це встановлює поточну дату 31. Поточний місяць - вересень, у якого 30 днів, тому він обертається.

Якби ви роздруковували дату після цього моменту, це означало б 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

мені подобається ця відповідь, тому що вона надає правильне рішення вгорі, а потім пояснює, чому непрацездатне рішення не працює ...
Кіп,

7

Причина такої поведінки та способи її уникнення були достатньо пояснені.

Але справжньою помилкою вашого коду є те, що ви не повинні використовувати конструктор за замовчуванням: new Date (). Ваш код приведе до дати 13 грудня з поточним часом. Сумніваюся, це те, що ти хочеш. Ви повинні використовувати конструктор Date, який у якості параметрів бере рік, місяць та день.


1
Я припускаю, що це мало бути коментарем прийнятої відповіді?
Дунайський моряк

Не зовсім. Це відповідь на питання "Що я зробив неправильно?"
Флоріан F

-1

Відповіді дали зрозуміти, що правильним порядком для встановлення дати є:

  • setFullYear ()
  • setMonth ()
  • setDate ()

Я просто хочу зазначити, що важливо також встановити рік спочатку, через 29 лютого у високосних роках.


1
Ні. Порядок не гарантує, що дату буде встановлено правильно. Дивіться коментарі нижче прийнятих та найбільш голосованих відповідей.
Салман,

1
Якщо ваша дата початку - 31 число, і ви встановите для нього місяць із меншою кількістю (наприклад, 30) днів, ви потрапите в наступний місяць. Тож цього просто недостатньо. Щоб бути в безпеці, перед встановленням місяця слід встановити дату не вище 28. І нарешті знову встановіть дату до остаточного значення, якщо воно вище.
барт

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

Передайте значення як ціле число, а не рядок .. воно поверне u правильне значення ..


Оновлення - наведений вище опис неправильний .. основна проблема полягала в тому, що вам потрібно було поставити ці три рядки в належній послідовності .. Навіть після того, як я виправив послідовність, забув виправити опис ..: P


Ні, ні, ось мій тест у chrome console: var dt = new Date (); невизначений dt.setDate (31); 1412157761255 dt.setMonth (11); 1417431761255 dt.setFullYear (2014); 1417431761255 dt понеділок 01 грудня 2014 12:02:41 GMT + 0100 (Париж, Мадрид)
користувач2859409

6
Це не має нічого спільного з типом аргументу і всім, що пов’язане з послідовністю. Ви згадуєте послідовність так, ніби це була другорядна річ ...
dee-see

1
Поки цей код працює , ви дали неправильне пояснення, чому.
Дунайський моряк
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.