Dlaczego argument miesiąca mieści się w zakresie od 0 do 11 w konstruktorze Date w JavaScript?

128

Podczas inicjowania nowego Dateobiektu w JavaScript za pomocą poniższego wywołania dowiedziałem się, że argument miesiąca liczy się od zera.

new Date(2010, 3, 1);  // that's the 1st April 2010!

Dlaczego argument miesiąca zaczyna się od 0? Z drugiej strony argument dzień miesiąca (ostatni) to liczba od 1 do 31. Czy są ku temu dobre powody?

Agnel Kurian
źródło
96
To tylko po to, żebyś był na palcach.
SeanJA
4
Jeden, który jest również indeksowany przez zero, to the Day of the week (integer)0-6
SeanJA
Ponieważ został zakodowany dla maszyn, a nie dla ludzi. Ale nadal jest to ogromne źródło błędów, ponieważ dużo kodu jest (nadal) napisane przez ludzi :)
Christophe Roussy
4
@Christophe ten sam argument powinien odnosić się również do dnia i roku.
Agnel Kurian
2
@ChristopheRoussy tak, skoro został zakodowany dla maszyn, to po co indeksować dni od 1?
user151496

Odpowiedzi:

55

To stara (prawdopodobnie niefortunna, prawdopodobnie umierająca) tradycja w świecie programowania, patrz stara standardowa (POSIX) funkcja czasu lokalnego w C http://linux.die.net/man/3/localtime

leonbloy
źródło
14
DateObiekt JS został przeportowany z Javy 1.0, dlatego. Dziedziczenie wszystkich jego wad ... stackoverflow.com/questions/344380/
c69
1
Masz rację, tradycje są zwykle całkowicie niespójne, a często czasami irracjonalne i naprawdę mam nadzieję, że takie „złe” tradycje naprawdę umierają ...
henon
1
jest rok 2019 i naprawiam problem związany z tym zachowaniem, tak długo, jak frameworki tak kątowe i języki jak javascript nie uznają tego za przestarzałe, to nadal będzie się działo - zachęcam do komentowania w roku 2025 i dalej ;-)
Mauricio Gracia Gutierrez
To tradycja, która zawsze sprawia, że ​​spędzam czas na debugowaniu problemów z datami ... Zastanawiam się, ile zmarnowanych godzin pracy spowodowała ta tradycja.
Vedmant
102

Prawdziwą odpowiedzią na to pytanie jest to, że zostało skopiowane java.util.Date, co również miało to dziwactwo. Dowód można znaleźć na Twitterze od Brendana Eicha - gościa, który pierwotnie zaimplementował JavaScript (w tym Dateobiekt):

https://twitter.com/BrendanEich/status/481939099138654209

pierwszy tweet

https://twitter.com/BrendanEich/status/771006397886533632

drugi tweet

Stało się to w 1995 roku, a JDK 1.0 był w wersji beta. Został uruchomiony w 1996 r. W 1997 r. Pojawił się JDK 1.1, który zdezaktualizował większość funkcji java.util.Date, przenosząc je do java.util.Calendar, ale nawet to nadal miało miesiące od zera. Deweloperzy, którzy mieli dość tego, stworzyli bibliotekę Joda-Time , która ostatecznie doprowadziła do java.timepakietu wypalonego w Javie 8 (2014).

Krótko mówiąc, uzyskanie przez Javę prawidłowo zaprojektowanego wbudowanego interfejsu API daty / czasu zajęło 18 lat, ale JavaScript wciąż tkwi w mrocznych czasach. Rzeczywiście mamy doskonałe biblioteki, takie jak Moment.js , date-fns i js-joda . Ale na razie nie ma nic więcej niż Datewbudowany język. Miejmy nadzieję, że to się zmieni w najbliższej przyszłości.

Matt Johnson-Pint
źródło
24
Ach ... Dobra stara metodologia Demo-Driven Development.
Álvaro González
@ ÁlvaroGonzález Obwiniłbym oryginalnego programistę JDK 1.0, który go przedstawił.
barell
30

Wszystko oprócz dnia miesiąca jest oparte na 0, zobacz tutaj pełną listę, w tym zakresy :)

Właściwie to dni oparte na 1 są tutaj dziwakami ... dość dziwne. Dlaczego to się stało? Nie wiem ... ale prawdopodobnie zdarzyło się to samo spotkanie, które otynkowali i zdecydowali, że średniki są opcjonalne.

Nick Craver
źródło
1
Dni oparte na jedynkach są prawdopodobnie spowodowane tym, że nikt przy zdrowych zmysłach nigdy nie utworzyłby tablicy nazw ciągów dla dni (np. { "first", "second", "third", ..., "twenty-seventh", ... }) I nie próbowałby indeksować jej według tm_mday. Z drugiej strony, może po prostu widzieli absolutną użyteczność w robieniu przez jeden błąd regularnego zdarzenia.
D.Shawley
Dlaczego lata nie są oparte na 0?
Vedmant
5

Rok ma zawsze 12 miesięcy, więc wczesne implementacje C mogły używać statycznej tablicy o stałej szerokości z indeksami 0..11.

Jonathan Julian
źródło
2
Implementacja Java Date / Calendar utrzymuje obsługę niektórych kalendarzy przez dodatkowy miesiąc. en.wikipedia.org/wiki/Undecimber
Pointy
4

Tak jest też w javie .. Prawdopodobnie aby przekonwertować int na string (0 - jan ,, 1-feb), zakodowali w ten sposób .. ponieważ mogą mieć tablicę ciągów (indeksowanych od 0) nazw miesięcy i tych miesięcy liczby, jeśli zaczynają się od 0, łatwiej będzie zmapować je na ciągi miesięcy.

raj
źródło
3

Wiem, że tak naprawdę nie jest to odpowiedź na pierwotne pytanie, ale chciałem tylko pokazać moje preferowane rozwiązanie tego problemu, którego nigdy nie zapamiętuję, ponieważ pojawia się od czasu do czasu.

Mała funkcja zerofill załatwia sprawę, wypełniając zera w razie potrzeby, a miesiąc jest właśnie +1dodawany:

function zerofill(i) {
    return (i < 10 ? '0' : '') + i;
}

function getDateString() {
    const date = new Date();
    const year = date.getFullYear();
    const month = zerofill(date.getMonth()+1);
    const day = zerofill(date.getDate());
    return year + '-' + month + '-' + day;
}

Ale tak, Date ma dość nieintuicyjny interfejs API, śmiałem się, kiedy czytałem Twitter Brendana Eicha.

Christof Kälin
źródło
2

Mogli traktować miesiące jako wyliczenie (pierwszy indeks to 0), a dni nie, ponieważ nie mają skojarzonej z nimi nazwy.

A raczej myśleli, że liczba dni jest rzeczywistą reprezentacją dnia (tak samo, jak miesiące są przedstawiane jako liczby w dacie takiej jak 12/31), tak jakbyś mógł wykonać wyliczenie z liczbami jako zmiennymi, ale w rzeczywistości Oparte na 0.

Więc właściwie dla miesięcy, być może myśleli, że właściwą reprezentacją wyliczenia będzie użycie nazwy miesiąca zamiast liczb, i zrobiliby to samo, gdyby dni miały reprezentację nazw. Wyobraź sobie, że zamiast 5 stycznia, 6 stycznia itd. Powiedzielibyśmy 5 stycznia, 6 stycznia itd., To być może również wyliczaliby liczbę dni od 0 ...

Być może podświadomie myśleli o wyliczeniu przez miesiące, takie jak {styczeń, luty, ...} i przez dni jako {jeden, dwa, trzy, ...}, z wyjątkiem dni, w których podajesz dzień jako liczbę, a nie nazwę, jak 1 za jeden itd., więc nie można zacząć od 0 ...

Pat-Laugh
źródło
Powinieneś podwójną klasę do psychologa. To wciąż błąd, który popełnili, ale przynajmniej teraz rozumiemy, dlaczego to zrobili.
Zesty
0

To może być wada, ale jest również bardzo przydatne, gdy chcesz przedstawić miesiące lub dzień tygodnia jako ciąg znaków, możesz po prostu utworzyć tablicę, taką jak ['jan,' feb '... itd.] [New Date () .getMonth ()] zamiast ['', 'jan', feb ... etc] [new Date (). getMonth ()] or ['jan', 'feb' ... etc] [new Date ( ) .getMonth () - 1]

dni miesiąca nie są zwykle nazwane, więc nie będziesz tworzyć tablic z nazwami dla nich. W tym przypadku 1-31 jest łatwiejszy w obsłudze, więc za każdym razem musisz odejmować 1 ...

Rogier
źródło
nie całkiem. Możesz łatwo odjąć jeden. To stwarza więcej problemów niż rozwiązuje, ponieważ teraz, kiedy robisz matematykę z datami, musisz raczej często wykonywać określone operacje na miesiącu.
Rey