Чому аргумент місяця коливається від 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 той самий аргумент має застосовуватися і до дня та року.
Агнел Куріан

2
@ChristopheRoussy Так, якщо це було закодовано для машин, навіщо індексувати дні з 1 тоді?
користувач151496

Відповіді:


55

Це стара (можливо , нещасна, ймовірно , вмирає) традиція в світі програмування, см старого стандарту (POSIX) LocalTime C функції http://linux.die.net/man/3/localtime


14
DateОб'єкт JS був перенесений з Java 1.0, ось чому. Успадкувавши всі свої недоліки ... stackoverflow.com/questions/344380 / ...
C69

1
Ви маєте рацію, традиції зазвичай абсолютно непослідовні і часто бувають ірраціональними, і я б дуже сподівався, що такі "погані" традиції насправді вмирають ...
henon

1
це 2019 , і я фіксуючи проблему , пов'язану з цим поведінкою, тому до тих пір , як рамки , як кутові і мови , як Javascript Dont принизити це він все одно буде відбуватися - НЕ соромтеся Coment в 2025 році і на ;-)
Маурісіо Gracia Gutierrez

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

102

Справжня відповідь на це запитання полягає в тому, що воно було скопійовано з того java.util.Date, в якому також була ця химерність. Доказ можна знайти у Twitter від Брендана Ейха - хлопця, який спочатку впровадив JavaScript (включаючиDate об’єкт):

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

перший твіт

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

другий твіт

Це сталося в 1995 році, і JDK 1.0 був у бета-версії. У 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. Знову ж таки, можливо, вони просто побачили абсолютну корисність у виведенні одними помилками регулярного явища.
Д.Шоулі

Вони чому роки не базуються на 0?
Ведмант

5

Завжди є 12 місяців на рік, тому на ранніх впровадженнях C можна було б використовувати статичний масив з фіксованою шириною з індексами 0..11.


2
Реалізація дати / календаря Java підтримує підтримку додаткового місяця для деяких календарів. en.wikipedia.org/wiki/Undecimber
Pointy

4

Це як у Java теж .. Ймовірно, для перетворення int в рядок (0 - січ, 1-феб) вони закодували таким чином .. тому що вони можуть мати масив рядків (індексується від 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), а дні не з тих пір, коли вони не мають з ними імені.

А точніше, вони думали, що число дня є фактичним поданням дня (так само, як місяці представлені як числа в такій даті, як 12/31), як якщо б ви могли зробити перерахування цифрами як змінні, але насправді На основі 0.

Так, власне, місяці, можливо, думали, що правильним перелічуванням буде використання імені місяця замість чисел, і вони зробили б те саме, якби дні мали представлення імені. Уявіть собі, якби ми сказали п'ять січня, шостий січень, замість 5 січня, 6 січня тощо.

Можливо, підсвідомо вони думали про перерахування місяцями як {січень, лютий, ...}, а дні як {один, два, три, ...}, за винятком днів, коли ви отримуєте доступ до дня як числа, а не до імені, як 1 для Один і т.д., так що неможливо почати з 0 ...


Вам слід подвійного класу до психолога. Це все ж помилка, яку вони зробили, але принаймні зараз ми розуміємо, чому вони це зробили.
Zesty

0

Це може бути вадою, але це також дуже зручно, коли ви хочете зобразити місяці або день тижня як рядок, ви можете просто створити масив на зразок ['jan,' feb '... тощо] [new Date () .getMonth ()] замість ['', 'jan', feb ... тощо] [нова дата (). getMonth ()] або ['jan', 'feb' ... тощо] [нова дата ( ) .getMonth () - 1]

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


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