В 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 = newString[12]; // and populate... Stringname= 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... иначе говоря, обойти основную проблему.
Теперь давайте подумаем о проблеме с месяцами 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: Потому что месяцы имеют названия, а дни месяца - нет.