Почему аргумент месяца находится в диапазоне от 0 до 11 в конструкторе даты JavaScript?

128

При инициализации нового Dateобъекта в JavaScript с помощью приведенного ниже вызова я обнаружил, что аргумент месяца отсчитывается, начиная с нуля.

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

Почему аргумент месяца начинается с 0? С другой стороны, аргумент дня месяца (последний) - это число от 1 до 31. Есть ли для этого веские причины?

Агнель Куриан
источник
96
Просто чтобы держать вас в тонусе.
SeanJA
4
Один, который также имеет нулевой индекс, это the Day of the week (integer)0-6
SeanJA
Потому что он был написан для машин, а не для людей. Но это по-прежнему огромный источник ошибок, потому что большая часть кода (все еще) написана людьми :)
Кристоф Русси,
4
@Christophe тот же аргумент должен применяться и к дню и году.
Agnel Kurian 06
2
@ChristopheRoussy Да, если он был написан для машин, зачем тогда индексировать дни с 1?
user151496

Ответы:

55

Это старая (вероятно, неудачная, возможно, умирающая) традиция в мире программирования, см. Старую стандартную (POSIX) функцию локального времени C http://linux.die.net/man/3/localtime

leonbloy
источник
14
JS- Dateобъект был перенесен из Java 1.0, поэтому. Унаследовав все его недостатки ... stackoverflow.com/questions/344380/…
c69
1
Вы правы, традиции обычно совершенно непоследовательны и часто иррациональны, и я действительно надеюсь, что такие «плохие» традиции действительно умирают ...
henon 07
1
- 2019 год, и я исправляю проблему, связанную с этим поведением, так что пока фреймворки, такие как angular и языки, такие как javascript, не устаревают, это все равно произойдет - не стесняйтесь комментировать в 2025 году и далее ;-)
Маурисио Грасиа Гутьеррес,
Это традиция, которая всегда заставляет меня тратить время на отладку проблем с датами ... Интересно, сколько миллионов потраченных впустую рабочих часов вызвала эта традиция.
Ведмант
102

Настоящий ответ на этот вопрос заключается в том, что он был скопирован с сайта java.util.Date, который также имел эту причуду. Доказательство можно найти в Twitter от Брендана Эйха - парня, который изначально реализовал JavaScript (включая Dateобъект):

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

первый твит

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

второй твит

Это произошло в 1995 году, и JDK 1.0 находился в стадии бета-тестирования. Он был запущен в 1996 году. В 1997 году вышел JDK 1.1, который устарел для подавляющего большинства функций java.util.Date, переместив их на java.util.Calendar, но даже в нем все еще оставались месяцы с нулевым отсчетом. Разработчики, которым это надоело, создали библиотеку Joda-Time , которая в конечном итоге привела к java.timeпакету, встроенному в Java 8 (2014).

Короче говоря, Java потребовалось 18 лет, чтобы получить правильно спроектированный встроенный API даты / времени, но JavaScript все еще застрял в темных веках. У нас действительно есть отличные библиотеки, такие как Moment.js , date-fns и js-joda . Но на данный момент в язык нет ничего, кроме Dateвстроенного. Надеюсь, это изменится в ближайшем будущем.

Мэтт Джонсон-Пинт
источник
24
Ах ... Старая добрая методология разработки на основе демонстраций.
Альваро Гонсалес
@ ÁlvaroGonzález Я бы винил оригинального разработчика JDK 1.0, который представил его в первую очередь.
Barell
30

Все, кроме дня месяца, основано на 0, см. Полный список, включая диапазоны :)

На самом деле странными здесь являются дни с отсчетом 1 ... как ни странно. Почему это было сделано? Я не знаю ... но, вероятно, это случилось на той же встрече, которую они намазали и решили, что точка с запятой не обязательна.

Ник Крейвер
источник
1
Дни, основанные на единицах, вероятно, связаны с тем, что никто в здравом уме никогда не создаст массив строковых имен для дней (например, { "first", "second", "third", ..., "twenty-seventh", ... }) и попытается проиндексировать его по tm_mday. С другой стороны, возможно, они просто увидели абсолютную полезность в том, чтобы регулярно допускать одну ошибку.
Д.Шоули,
Они почему годы не отсчитываются?
Ведмант
5

В году всегда 12 месяцев, поэтому ранние реализации C могли использовать статический массив фиксированной ширины с индексами 0..11.

Джонатан Джулиан
источник
2
Реализация даты / календаря Java поддерживает дополнительный месяц для некоторых календарей. en.wikipedia.org/wiki/Undecimber
Pointy
4

То же самое и в java .. Вероятно, чтобы преобразовать int в строку (0 - jan ,, 1-feb), они закодировали таким образом .. потому что у них может быть массив строк (проиндексированных с 0) названий месяцев и этого месяца числа, если они начинаются с 0, будет намного проще сопоставить строки месяца ..

Радж
источник
3

Я знаю, что это не совсем ответ на исходный вопрос, но я просто хотел показать вам мое предпочтительное решение этой проблемы, которое я никогда не запоминаю, поскольку оно время от времени всплывает.

Небольшая функция zerofill выполняет трюк, заполняя нули там, где это необходимо, а месяц просто +1добавляется:

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;
}

Но да, у Date довольно неинтуитивный API, я смеялся, когда читал Twitter Брендана Эйха.

Кристоф Келин
источник
2

Они могли бы считать месяцы перечислением (первый индекс равен 0), а дни - нет, поскольку с ними не было связано имя.

Или, скорее, они думали, что номер дня является фактическим представлением дня (точно так же, как месяцы представлены в виде чисел в дате, например, 31 декабря), как если бы вы могли сделать перечисление с числами в качестве переменных, но на самом деле 0 на основе.

Так что на самом деле, в течение месяцев, возможно, они думали, что правильным представлением в перечислении будет использование имени месяца вместо чисел, и они бы поступили так же, если бы дни имели представление имени. Представьте, что если бы мы произнесли 5 января, 6 января, а не 5 января, 6 января и т. Д., Тогда, возможно, они бы тоже провели нумерацию дней ...

Возможно, подсознательно они думали о перечислении месяцев как {Январь, Февраль, ...} и дней как {Один, Два, Три, ...}, за исключением дней, когда вы обращаетесь к дню как к числу, а не к имени, например, 1 для одного и т. д., поэтому невозможно начать с 0 ...

Пат-Смеяться
источник
Вам следует пройти двойной курс к психологу. Это все еще ошибка, которую они совершили, но, по крайней мере, теперь мы понимаем, почему они ее сделали.
Zesty
0

Это может быть недостаток, но это также очень удобно, когда вы хотите представить месяцы или день недели в виде строки, вы можете просто создать массив вроде ['jan,' feb '... и т. Д.] [New Date () .getMonth ()] вместо ['', 'jan', feb ... и т. д.] [new Date (). getMonth ()] или ['jan', 'feb' ... и т. д.] [new Date ( ) .getMonth () - 1]

дни месяца обычно не называются, поэтому вы не будете создавать массивы с именами для них. В этом случае с 1-31 легче справиться, поэтому вам нужно каждый раз вычитать 1 ...

Рогир
источник
на самом деле, нет. Вы легко можете просто вычесть один. Это создает больше проблем, чем решает, потому что теперь, когда вы занимаетесь математикой с датами, вам довольно часто приходится делать определенные манипуляции с месяцем.
Rey