Вопрос-ответ

Why is January month 0 in Java Calendar?

Почему январь месяц 0 в Java Calendar?

В java.util.Calendar январь определяется как месяц 0, а не как месяц 1. Есть ли для этого какая-то конкретная причина?

Я видел, что многих людей это смущает...

Переведено автоматически
Ответ 1

Это всего лишь часть ужасного беспорядка, который представляет собой Java date / time API. Перечисление того, что с ним не так, заняло бы очень много времени (и я уверен, что не знаю половины проблем). По общему признанию, работать с датами и временем сложно, но в любом случае.

Сделайте себе одолжение и используйте вместо этого Joda Time или, возможно, JSR-310.

РЕДАКТИРОВАТЬ: Что касается причин, по которым - как отмечалось в других ответах, это вполне может быть связано со старыми API C или просто общим ощущением начала всего с 0... за исключением того, что дни начинаются с 1, конечно. Я сомневаюсь, что кто-либо за пределами первоначальной команды разработчиков действительно мог бы назвать причины - но опять же, я бы призвал читателей не так сильно беспокоиться о том, почему были приняты плохие решения, а посмотреть на всю гамму гадостей в java.util.Calendar и найти что-нибудь получше.

Один момент, который говорит в пользу использования индексов на основе 0, заключается в том, что это упрощает такие вещи, как "массивы имен":

// I "know" there are 12 months
String[] monthNames = new String[12]; // and populate...
String name = monthNames[calendar.get(Calendar.MONTH)];

Конечно, это завершается ошибкой, как только вы получаете календарь с 13 месяцами... но, по крайней мере, указанный размер соответствует ожидаемому количеству месяцев.

Это не веская причина, но это повод...

РЕДАКТИРОВАТЬ: В качестве комментария запрашиваются некоторые идеи о том, что, по моему мнению, не так с датой / календарем:


  • Неожиданные основания (1900 в качестве базового года в Date, по общему признанию, для устаревших конструкторов; 0 в качестве базового месяца в обоих)

  • Изменчивость - использование неизменяемых типов намного упрощает работу с действительно эффективными значениями

  • Недостаточный набор типов: приятно иметь Date и Calendar как разные вещи, но разделение значений "local" и "zoned" отсутствует, как и разница между датой / временем и date vs time

  • API, который приводит к уродливому коду с магическими константами вместо четко названных методов

  • API, о котором очень сложно рассуждать - все дело в том, когда что-то пересчитывается и т. Д

  • Использование конструкторов без параметров по умолчанию для "now", что приводит к труднодоступному для тестирования коду

  • Date.toString() Реализация, которая всегда использует локальный часовой пояс системы (до сих пор это сбивало с толку многих пользователей Stack Overflow)

Ответ 2

Потому что делать математику с месяцами намного проще.

1 месяц после декабря - это январь, но чтобы вычислить это в обычном режиме, вам пришлось бы взять номер месяца и выполнить математические вычисления

12 + 1 = 13 // What month is 13?

Я знаю! Я могу быстро исправить это, используя модуль 12.

(12 + 1) % 12 = 1

Это работает просто отлично в течение 11 месяцев до ноября...

(11 + 1) % 12 = 0 // What month is 0?

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

((11 - 1 + 1) % 12) + 1 = 12 // Lots of magical numbers!

Теперь давайте подумаем о проблеме с месяцами 0-11.

(0 + 1) % 12 = 1 // February
(1 + 1) % 12 = 2 // March
(2 + 1) % 12 = 3 // April
(3 + 1) % 12 = 4 // May
(4 + 1) % 12 = 5 // June
(5 + 1) % 12 = 6 // July
(6 + 1) % 12 = 7 // August
(7 + 1) % 12 = 8 // September
(8 + 1) % 12 = 9 // October
(9 + 1) % 12 = 10 // November
(10 + 1) % 12 = 11 // December
(11 + 1) % 12 = 0 // January

Все месяцы работают одинаково, и обходной путь не требуется.

Ответ 3

Языки на основе C в некоторой степени копируют C. tm Структура (определенная в time.h) имеет целочисленное поле tm_mon с (прокомментированным) диапазоном от 0 до 11.

Языки на основе C запускают массивы с индексом 0. Это было удобно для вывода строки в массиве названий месяцев с tm_mon в качестве индекса.

Ответ 4

На этот вопрос было много ответов, но я все равно выскажу свое мнение по этому вопросу. Причина такого странного поведения, как указывалось ранее, исходит из POSIX C, time.h где месяцы хранились в int с диапазоном 0-11. Чтобы объяснить почему, посмотрите на это так; годы и дни считаются числами в разговорном языке, но у месяцев есть свои названия. Итак, поскольку январь - это первый месяц, он будет сохранен как смещение 0, первый элемент массива. monthname[JANUARY] было бы "January". Первый месяц в году - это элемент массива first month .

С другой стороны, номера дней, поскольку у них нет имен, сохранение их в int как 0-30 сбивало бы с толку, добавляло бы много day+1 инструкций для вывода и, конечно же, приводило бы к множеству ошибок.

При этом несоответствие сбивает с толку, особенно в javascript (который также унаследовал эту "функцию"), языке сценариев, где это должно быть абстрагировано далеко от языка.

TL; DR: Потому что месяцы имеют названия, а дни месяца - нет.

java