Если ты работал с java.util.Date или Calendar, то сталкивался с этими проблемами. Мутабельные объекты, месяцы с нуля, запутанный API. В Java 8 появился java.time (JSR-310), и это то, что должно было быть с самого начала.
🔹 Instant — source of truth
Instant now = Instant.now(); // 2024-01-15T19:00:00Z
// Из Unix timestamp
Instant fromSeconds = Instant.ofEpochSecond(1705341600L);
// Получить timestamp
long epochMilli = now.toEpochMilli();
// Арифметика
Instant later = now.plusSeconds(3600); // +1 час
// Наносекундная точность (не то что Date с миллисекундами)
long nanos = now.getNano();
Храни в БД именно Instant. Никакой TZ-зависимости и никаких сюрпризов.
🔹 LocalDateTime, когда TZ не нужна
LocalDateTime dt = LocalDateTime.of(2024, 1, 15, 19, 0, 0);
LocalDateTime parsed = LocalDateTime.parse("2024-01-15T19:00:00");
// ✅ Юзер ввёл дату без TZ
// ✅ Бизнес-логика без мультирегиональности
// ❌ Хранение в БД — используй Instant
// ❌ API-ответы — неоднозначно без TZ
🔹 ZonedDateTime для пользователей
ZonedDateTime ny = ZonedDateTime.now(ZoneId.of("America/New_York"));
ZonedDateTime tokyo = ZonedDateTime.now(ZoneId.of("Asia/Tokyo"));
// Конвертация между TZ — один и тот же момент времени
ZonedDateTime london = ny.withZoneSameInstant(ZoneId.of("Europe/London"));DST обрабатывается автоматически:
// 10 марта 2:30 AM не существует (переход на летнее время)
LocalDateTime nonExistent = LocalDateTime.of(2024, 3, 10, 2, 30);
ZonedDateTime adjusted = nonExistent.atZone(ZoneId.of("America/New_York"));
// → автоматически станет 3:30 AM EDT
🔹 ZonedDateTime vs OffsetDateTime
// ZonedDateTime — знает правила DST, для будущих дат
ZonedDateTime zdt = ZonedDateTime.now(ZoneId.of("America/New_York"));
// OffsetDateTime — просто смещение, без DST. Для прошлых событий и API
OffsetDateTime odt = OffsetDateTime.now(ZoneOffset.ofHours(-5));
🔹 DateTimeFormatter для форматирования и парсинга
LocalDateTime dt = LocalDateTime.of(2024, 1, 15, 19, 0, 0);
// Predefined
dt.format(DateTimeFormatter.ISO_LOCAL_DATE_TIME); // "2024-01-15T19:00:00"
dt.format(DateTimeFormatter.BASIC_ISO_DATE); // "20240115"
// Custom
DateTimeFormatter fmt = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
dt.format(fmt); // "2024-01-15 19:00:00"
// Парсинг с обработкой ошибок
public static Optional<LocalDateTime> parse(String s) {
try {
return Optional.of(LocalDateTime.parse(s, fmt));
} catch (DateTimeParseException e) {
return Optional.empty();
}
}
🔹 Шпаргалка по токенам
yyyy → 2024 MM → 01 dd → 15
HH → 19 (24h) hh → 07 (12h) mm → 00
ss → 00 SSS → 123 a → PM
z → EST Z → -0500 VV → America/New_York
🔹 Duration vs Period
// Duration — точный временной интервал
Duration duration = Duration.ofHours(24); // ровно 86400 секунд
// Period — календарный интервал
Period period = Period.ofDays(1); // 1 день (может быть 23 или 25 ч. при DST!)
// Оба работают с LocalDateTime, но семантика разная:
dt.plus(Duration.ofHours(24)); // +86400 сек
dt.plus(Period.ofDays(1)); // +1 календарный день
🔹 Миграция с легаси
// Date → Instant
Instant instant = oldDate.toInstant();
// Instant → Date
Date date = Date.from(instant);
// Date → LocalDateTime
LocalDateTime ldt = oldDate.toInstant()
.atZone(ZoneId.systemDefault())
.toLocalDateTime();
══════ Навигация ══════
Вакансии • Задачи • Собесы
🐸 Библиотека джависта
#Enterprise