new Date () ustawiony na 31 grudnia 2014 wskazuje zamiast tego 1 grudnia

80

Próbuję przekonwertować ciąg na obiekt Date i działa przez wszystkie dni z wyjątkiem 31 grudnia, gdzie według obiektu jest napisane 1 grudnia zamiast 31. Nie mam pojęcia dlaczego. Oto mój JavaScriptkod:

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

ale moja wartość zmiennej to:

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

Jeśli zrobię to samo dla dowolnej innej daty, mój obiekt wróci do odpowiedniej wartości. Czy masz pojęcie, co zrobiłem źle?

user2859409
źródło
7
Masz przekazywać liczby całkowite do setMonth itp., A nie łańcuchy.
funkybro
15
możesz użyć Dateparametrów konstruktora bezpośrednio:new Date(2014, 11, 31)
pomeh
9
przy okazji. to nie jest 11 miesiąc listopad?
jnovacho
5
@JuhaUntinen Nie, data jest pomieszane, ponieważ miesięcy teraz ma tylko 30 dni.
Pan Lister,

Odpowiedzi:

85

setMonth powinien wcześniej setDate: ( nie jest bezpieczny przez miesiące krótsze niż 31 dni )

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

I setMonthjest drugi parametr może być również używany do ustawiania daty.

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


Jeśli konstruktor nie poda żadnych argumentów, użyje bieżącej daty i godziny zgodnie z ustawieniami systemu.

Tak więc użycie setMonthi setDateoddzielnie nadal spowodowałoby nieoczekiwany rezultat.

Jeśli ustawione wartości są większe niż ich zakres logiczny , wartość zostanie automatycznie dostosowana do wartości sąsiedniej .

Na przykład, jeśli dzisiaj jest 2014-09-30, to

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 */

Aby tego uniknąć, ustaw wartości bezpośrednio przy użyciu konstruktora.

var dt = new Date(2014, 11, 31);
xdazz
źródło
1
Właśnie się tego dowiedziałem, ale to nie ma dla mnie sensu
user2859409
15
@ user2859409 to prawdopodobnie dlatego, że jeśli nie ustawisz miesiąca jako pierwszy, zajmie to bieżący miesiąc, a następnie może czasami przejść do następnego (zgodnie z odpowiedzią Jakuba poniżej)
fbstj
3
Wahałbym się polecić ten pierwszy blok kodu na miesiące z mniej niż 31 dniami. Jeśli, na przykład, chcesz ustawić datę na 15 września, ale dziś jest 31 sierpnia, data zawinie się do następnego miesiąca i skończysz na 15 października. +1 dla drugiego bloku kodu: to jest lepszy sposób. Nie wiedziałem nawet, że setMonthistnieje dwuargumentowa forma .
Luke Woodward
10
Pamiętaj, że ustawienie miesiąca poprzedzającego dzień również może być nieprawidłowe. Jednak nie w tym przypadku. Jeśli jest 31 października, to setMonth (10) ustawi datę na 31 listopada, która zakończy się na 1 grudnia. SetDate (31) daje wynik 31 grudnia. Dlatego zawsze używaj 2-argumentowej setMonth ().
Florian F
1
+1, ale chciałbym podkreślić, że opcja dwóch miesięcy jest preferowana, aby zapobiec efektom ubocznym.
Brian
120

Rzecz w tym, że kiedy ustawiasz dzień pierwszy, nadal jesteś w bieżącym miesiącu, czyli wrześniu. Wrzesień ma tylko 30 dni, więc:

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 */
Jakub Michálek
źródło
22
+1 - To jest rodzaj robaka, który będzie uśpiony przez cały sierpień, a potem ugryzie cię w tyłek we wrześniu;)
Niet the Dark Absol
19
NIGDY nie jest właściwe ustawianie daty po jednym komponencie na raz, ponieważ zdarzają się przypadki awarii, w których dzień jest pierwszy, a miesiąc pierwszy, a prawdopodobnie 29.02. Musisz ustawić wszystkie trzy pola w tym samym czasie.
Jim Garrison,
5
+1 i powinna to być akceptowana odpowiedź, ponieważ wyjaśnia DLACZEGO należy ustawić miesiąc jako pierwszy. To bardzo javascriptowy WTF
Danubian Sailor
2
Powinien być podobny w innych językach, a nie „javascript WTF”.
Raidri wspiera Monikę
Dlaczego obiekt Date nie zgłasza się po ustawieniu nieprawidłowej daty?
jww
23

To dlatego, że pierwszą rzeczą, którą robisz, jest

dt.setDate(31)

To ustawia bieżącą datę na 31. Bieżący miesiąc to wrzesień, który ma 30 dni, więc jest zawijany.

Gdybyś miał wydrukować datę po tym punkcie, byłby to 1 października.

funkybro
źródło
12
Zabawne jest to, że pojawiło się to tylko dlatego, że próbował tego przez miesiąc z 30 dniami. Miesiąc później i wydawałoby się, że działa dobrze.
Peter Remmers,
13

Zakładając, że zamierzasz ustawić rok, miesiąc i datę jednocześnie, możesz użyć konstruktora dłuższej daty :

nowa data (rok, miesiąc, dzień, godzina, minuta, sekunda, milisekunda);

[…]

Jeśli podano co najmniej dwa argumenty, brakujące argumenty są ustawiane na 1 (jeśli brakuje dnia) lub 0 dla wszystkich pozostałych.

Więc napisałbyś:

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

Jak już ustalono, ustawienie jednej porcji daty naraz może spowodować przepełnienia:

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

Ponadto ustawienie miesiąca przed datą może nadal powodować nieoczekiwane przepełnienie (odpowiedzi zalecające zmianę kolejności metod są niepoprawne):

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
Salman A
źródło
Podoba mi się ta odpowiedź, ponieważ na górze podaje poprawne rozwiązanie, a następnie wyjaśnia, dlaczego zepsute rozwiązanie nie działa ...
Kip
7

Dokładnie wyjaśniono, dlaczego to zachowanie i jak go uniknąć.

Ale prawdziwym błędem w twoim kodzie jest to, że nie powinieneś używać domyślnego konstruktora: new Date (). Twój kod spowoduje wyświetlenie daty 13 grudnia z aktualną godziną. Wątpię, czy tego chcesz. Należy użyć konstruktora Date, który przyjmuje jako parametry rok, miesiąc i dzień.

Florian F
źródło
1
Przypuszczam, że miał to być komentarz do zaakceptowanej odpowiedzi?
Danubian Sailor,
Nie całkiem. To odpowiedź na pytanie "Co zrobiłem źle?"
Florian F,
-1

Odpowiedzi jasno wskazywały, że prawidłowa kolejność ustawiania daty to:

  • setFullYear ()
  • setMonth ()
  • ustawić datę()

Chcę tylko zaznaczyć, że ważne jest również, aby ustawić rok na początku, ponieważ 29 lutego jest latami letnimi.

henman
źródło
1
Nie. Zamówienie nie gwarantuje, że data zostanie ustawiona poprawnie. Zobacz komentarze poniżej zaakceptowanych i najczęściej głosowanych odpowiedzi.
Salman A,
1
Jeśli Twoją datą rozpoczęcia jest 31. miesiąc i ustawisz go na miesiąc z mniejszą liczbą dni (np. 30), skończysz w następnym miesiącu. Więc to po prostu nie wystarczy. Dla bezpieczeństwa należy ustawić datę nie wyższą niż 28 przed ustawieniem miesiąca. Na koniec ustaw datę ponownie na ostateczną wartość, jeśli jest wyższa.
bart
-3
var dt = new Date();
dt.setFullYear(2014);
dt.setMonth(11);
dt.setDate(31);

Przekaż wartość jako liczbę całkowitą, a nie łańcuch. Zwróci poprawną wartość u.


Aktualizacja - powyższy opis nie jest poprawny .. główny problem polegał na tym, że trzeba było ustawić te trzy linie w odpowiedniej kolejności .. Nawet po poprawieniu kolejności zapomniałem poprawić opis ..: P

Deepak Sharma
źródło
Nie, nie, oto mój test w konsoli chrome: var dt = new Date (); undefined dt.setDate (31); 1412157761255 dt.setMonth (11); 1417431761255 dt.setFullYear (2014); 1417431761255 dt pon 01 grudnia 2014 12:02:41 GMT + 0100 (Paryż, Madryt)
user2859409
6
Nie ma to nic wspólnego z typem argumentu, a wszystko z sekwencją. Wspominasz o sekwencji, jakby to była sprawa drugorzędna ...
zobacz
1
Chociaż ten kod działa , podałeś złe wyjaśnienie, dlaczego.
Danubian Sailor