Получить доступ

Дата и время: java.time

Почему java.time вытеснил Date/Calendar, машинное (Instant) и человеческое (LocalDateTime) время, часовые пояса, Duration/Period и потокобезопасный DateTimeFormatter.

Зачем java.time

Старые java.util.Date и Calendar — изменяемые и не потокобезопасные, с ловушками: у Date почти весь API устарел, у Calendar месяцы нумеруются с нуля (январь = 0), а SimpleDateFormat нельзя шарить между потоками. Это десятилетиями было источником багов.

java.time (JSR-310, Java 8) построен иначе: все типы неизменяемы и потокобезопасны, модель явная (отдельно момент, дата, время, зона), а API текучий и предсказуемый. Это стандарт де-факто; старый код переводят на него.

Машинное и человеческое время

Instant — момент на глобальной шкале (секунды/наносекунды от эпохи 1970-01-01T00:00:00Z, всегда UTC). Это «машинное» время: удобно хранить, сравнивать и логировать.

LocalDate (только дата), LocalTime (только время) и LocalDateTime (дата+время) — «человеческое» время БЕЗ зоны. LocalDateTime «2026-01-01 09:00» не задаёт конкретный момент, пока не привязан к зоне: в Москве и в Нью-Йорке это разные моменты.

Instant now = Instant.now();                 // момент в UTC
LocalDate today = LocalDate.now();           // дата без времени и зоны
LocalDateTime dt = LocalDateTime.of(2026, 1, 1, 9, 0); // без зоны — ещё не момент

Часовые пояса: ZoneId и ZonedDateTime

ZonedDateTime = LocalDateTime + ZoneId (например, Europe/Moscow): это уже конкретный момент с правилами перехода на летнее время. OffsetDateTime проще — дата-время с фиксированным смещением от UTC (+03:00), без правил DST.

Практическое правило: храните и передавайте моменты в UTC (Instant), а в местную зону переводите только при показе пользователю. Так вы избегаете ошибок на переходах летнего времени и между регионами.

ZonedDateTime msk = dt.atZone(ZoneId.of("Europe/Moscow"));
Instant instant = msk.toInstant();           // момент для хранения (UTC)
ZonedDateTime ny = instant.atZone(ZoneId.of("America/New_York")); // то же мгновение в другой зоне

Длительности: Duration и Period

Duration — машинная длительность в секундах и наносекундах (между Instant/LocalTime): «90 минут», «5 секунд». Period — календарная длительность в годах, месяцах и днях (между LocalDate): «2 месяца», «3 дня».

Разница не косметическая: Period.ofDays(1) и Duration.ofHours(24) могут дать разный результат на стыке перехода на летнее время, потому что календарный «день» не всегда равен 24 часам. Берите тип по смыслу: машинное время — Duration, календарь — Period.

Форматирование и разбор

Типы java.time умеют ISO-формат из коробки (toString → 2026-01-01T09:00). Для своих шаблонов есть DateTimeFormatter — и, в отличие от SimpleDateFormat, он неизменяемый и потокобезопасный, поэтому его держат в static-константе.

format(formatter) превращает дату в строку, parse(text, formatter) — строку в дату. Для локализованного вывода задают Locale; при разборе шаблон должен точно соответствовать входу, иначе будет DateTimeParseException.

static final DateTimeFormatter F = DateTimeFormatter.ofPattern("dd.MM.yyyy HH:mm");
String s = dt.format(F);                  // "01.01.2026 09:00"
LocalDateTime back = LocalDateTime.parse(s, F);

Неизменяемость и совместимость с legacy

Все типы java.time неизменяемы: plusDays, withYear и т.п. возвращают НОВЫЙ объект, исходный не меняется — забытое присваивание (dt.plusDays(1) без сохранения) частая ошибка. Зато их безопасно шарить между потоками.

С legacy-кодом наводят мосты: new Date() ↔ Date.toInstant()/Date.from(Instant); java.sql-типы конвертируются своими методами. Новый код пишут на java.time, а конверсии делают только на границе со старым API.

LocalDate tomorrow = today.plusDays(1);  // НОВЫЙ объект; today не изменился
Instant i = new java.util.Date().toInstant(); // мост из legacy

Как отвечать на собеседовании

Объясните, почему java.time вытеснил Date/Calendar (неизменяемость, потокобезопасность, явная модель, ловушки старого API). Различите Instant (машинный момент в UTC) и LocalDateTime (без зоны), ZonedDateTime/ZoneId и правило «хранить в UTC». Разведите Duration (секунды) и Period (календарь), упомяните потокобезопасный DateTimeFormatter против SimpleDateFormat и неизменяемость (методы возвращают новый объект).

Вопросы по теме

Читайте также

Закрытая бета

Знать тему — половина дела

На живом собеседовании sotto слышит вопрос интервьюера и показывает короткий ответ и план. Оставьте контакт — пришлём доступ и промокод.

  • Промокод на 2 часа — сверх пробных 30 минут
  • Программа для Windows — скачать сразу, войти — через Яндекс ID или VK ID
  • Прямая связь с разработчиком: что улучшить — сделаем