W3docs

Класс Calendar в Java

Устаревший класс java.util.Calendar и GregorianCalendar — принцип работы и связь с java.time.

java.util.Calendar — вторая половина устаревшей пары классов для работы с датой и временем. Если java.util.Date является лишь обёрткой над long-значением миллисекунд с начала эпохи, то Calendar — это класс, который знает, на какой год, месяц и день приходится данная миллисекунда. Он был добавлен в Java 1.1, чтобы вынести календарную арифметику из Date — именно поэтому большинство методов доступа к полям Date помечены как устаревшие.

В современном коде следует использовать java.time. Тем не менее Calendar по-прежнему встречается: в старых кодовых путях, в библиотеках, написанных до Java 8, и в JDBC-драйверах, которые не были обновлены. Вам нужно уметь его читать, преобразовывать и двигаться дальше. На этой странице рассматривается, как создать Calendar, безопасно читать его поля (обратите внимание на нумерацию месяцев с нуля), выполнять календарную арифметику и, что важнее всего, переходить к современному API.

Calendar — абстрактный класс

Calendar сам по себе является абстрактным классом. Вы никогда не вызываете new Calendar(...). Экземпляр получается через фабричный метод:

Calendar cal = Calendar.getInstance();

Он возвращает конкретный подкласс — почти всегда GregorianCalendar — с уже загруженным текущим временем, часовым поясом по умолчанию и локалью по умолчанию. При необходимости можно задать параметры явно:

Calendar cal = Calendar.getInstance(TimeZone.getTimeZone("UTC"), Locale.US);

У GregorianCalendar есть и публичные конструкторы, однако принято использовать фабричный метод.

Константы полей

Calendar предоставляет доступ ко всему через целочисленные константы полей и обобщённый метод get(int field):

ПолеЗначениеДиапазон
Calendar.YEARГодполный год, например 2026
Calendar.MONTHМесяц0–11 (January = 0)
Calendar.DAY_OF_MONTHДень месяца1–31
Calendar.DAY_OF_WEEKДень недели1–7 (Sunday = 1)
Calendar.HOUR_OF_DAYЧас0–23
Calendar.MINUTEМинута0–59
Calendar.SECONDСекунда0–59
Calendar.MILLISECONDМиллисекунда0–999

В этой таблице скрываются две ловушки: MONTH отсчитывается с нуля (Calendar.JANUARY == 0), а DAY_OF_WEEK начинается с воскресенья. Ошибки на единицу в устаревшем коде почти всегда возникают именно здесь.

Установка значений и арифметика

set принимает поле и значение; add выполняет арифметику с учётом календаря и переносит переполнение в более старшие поля:

Calendar cal = Calendar.getInstance();
cal.set(2026, Calendar.MAY, 29);   // Y, M, D — month is zero-based
cal.add(Calendar.DAY_OF_MONTH, 5); // → 2026-06-03

roll делает то же самое поле за полем, но не переносит значение в более старшие поля — roll(DAY_OF_MONTH, 5) для 30 мая даст 4 мая, а не 4 июня. Это редко бывает нужным.

Экземпляры Calendar являются изменяемыми, поэтому передача такого объекта в метод означает передачу живой ссылки. Клонируйте объект перед тем, как раскрывать его вовне, так же как вы поступаете с Date.

Переход к java.time

Единственная причина, по которой сегодня стоит работать с Calendar, — это выйти из него. Для этого существуют два метода:

Instant when = cal.toInstant();
ZoneId  zone = cal.getTimeZone().toZoneId();
ZonedDateTime zdt = when.atZone(zone);

Начиная с ZonedDateTime, вам доступен весь современный API. Обратный путь:

Calendar cal = GregorianCalendar.from(zdt); // Java 8+

GregorianCalendar.from(ZonedDateTime) — поддерживаемый способ конвертации. Избегайте двойного преобразования через Date.

Пример

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

java— editable, runs on the server

Что следует вынести из результатов выполнения:

  • Calendar.MONTH для мая выводит 4. Нумерация месяцев с нуля — главный источник ошибок в устаревшем коде для работы с датами.
  • getInstance(TimeZone) привязывает экземпляр к часовому поясу — в отличие от Date, у которого часового пояса нет.
  • add(MONTH, 1) учитывает длину месяца; вы получаете правильный день следующего месяца, даже если месяцы не все по 30 дней.
  • cal.toInstant().atZone(cal.getTimeZone().toZoneId()) — однострочный переход к java.time.
  • GregorianCalendar.from(ZonedDateTime) позволяет вернуть Calendar в старый API без потери информации о часовом поясе.

Что дальше

На этом завершается Часть 14 — Дата и время. Следующая — Часть 15, Многопоточность и параллелизм, которая начинается с раздела Многопоточность в Java — модели, которая повлияла на все остальные API в этой книге.

Практика
Calendar установлен на 29 мая 2026 года и возвращает cal.get(Calendar.MONTH). Какое значение будет получено?
Calendar установлен на 29 мая 2026 года и возвращает cal.get(Calendar.MONTH). Какое значение будет получено?
Was this page helpful?