Класс LocalDateTime в Java: создание, форматирование и примеры - Вопросы

Всего: 6 вопросов

1. 

Что такое LocalDateTime в Java и как создать объект этого класса?

java.time.LocalDateTime (Java 8+) — неизменяемый потокобезопасный класс, который хранит дату и время без часового пояса: год, месяц, день, часы, минуты, секунды и наносекунды. По сути это LocalDate и LocalTime в одном объекте.

Публичного конструктора нет, объект создают фабричными методами:

  • LocalDateTime.of(2024, 3, 15, 14, 30) — по частям (секунды и наносекунды необязательны);
  • LocalDateTime.of(date, time), date.atTime(14, 30), time.atDate(date), date.atStartOfDay() — из готовых LocalDate и LocalTime;
  • LocalDateTime.parse("2024-03-15T14:30:45") — из строки ISO-8601;
  • LocalDateTime.now() — текущие дата и время.

toString() ставит между датой и временем букву T и не печатает нулевые секунды и наносекунды: LocalDateTime.of(2014, 9, 19, 14, 5) выводится как 2014-09-19T14:05. Некорректные значения (of(2024, 2, 30, 10, 0), час 24) сразу дают DateTimeException.

2. 

Почему LocalDateTime.parse("2024-03-15 10:30") выбрасывает исключение и как форматировать и разбирать LocalDateTime в своём формате?

Без форматтера parse() понимает только ISO-8601, где дату и время разделяет буква T: "2024-03-15T10:30". На позиции 10 он встречает пробел и выбрасывает DateTimeParseException: ... could not be parsed at index 10. Строка только с датой ("2024-03-15") тоже не разбирается.

Для своего формата нужен DateTimeFormatter:

DateTimeFormatter f = DateTimeFormatter.ofPattern("dd.MM.yyyy HH:mm");
String s = LocalDateTime.of(2024, 3, 15, 14, 30).format(f); // 15.03.2024 14:30
LocalDateTime dt = LocalDateTime.parse("15.03.2024 14:30", f);

Если в шаблоне нет времени ("dd.MM.yyyy"), разбор в LocalDateTime упадёт с Unable to obtain LocalDateTime from TemporalAccessor — разбирайте в LocalDate и вызывайте atStartOfDay(). Шаблон со смещением зоны (XXX, Z) даёт UnsupportedTemporalTypeException: Unsupported field: OffsetSeconds: зоны в объекте нет, сначала нужен atZone().

3. 

Как изменить и сравнить значения LocalDateTime?

Объект неизменяем: withYear()…withNano() и with(ChronoField, value) заменяют одно поле, plusDays(), plusHours(), minusMonths(), plus(n, ChronoUnit) сдвигают значение — и все возвращают новый LocalDateTime. Результат нужно присвоить: dt = dt.plusHours(1);.

В отличие от LocalTime, время не «заворачивается» в пределах суток: LocalDateTime.of(2024, 3, 15, 23, 30).plusMinutes(45) даёт 2024-03-16T00:15.

Сравнение — isBefore(), isAfter(), isEqual() или equals(), но не == (оно сравнивает ссылки). Класс реализует Comparable; результат compareTo() сравнивайте с нулём, а не с -1.

truncatedTo() отбрасывает лишнюю точность: truncatedTo(ChronoUnit.DAYS) — полночь того же дня, truncatedTo(ChronoUnit.MINUTES) — без секунд. Единицы больше суток (MONTHS) дают UnsupportedTemporalTypeException.

4. 

Как посчитать разницу между двумя LocalDateTime?

Есть два способа:

  • Duration.between(start, end) — длительность в часах, минутах и секундах, например PT8H30M;
  • ChronoUnit.X.between(start, end) — число полных единиц типа long, например ChronoUnit.MINUTES.between(start, end) = 510.

Неполные единицы отбрасываются: с 22:00 15 марта до 06:30 16 марта ChronoUnit.DAYS.between вернёт 0. Чтобы узнать, сменилось ли календарное число, сравнивайте даты: Period.between(start.toLocalDate(), end.toLocalDate()) даст P1D. Period.between(start, end) с аргументами LocalDateTime не скомпилируется — он принимает только LocalDate.

5. 

Чем LocalDateTime отличается от Instant и когда что выбирать?

LocalDateTime — дата и время «на часах» без зоны (2024-03-15T10:30): одно и то же значение в Москве и в Берлине соответствует разным моментам, поэтому само по себе оно момент времени не определяет. Instant — точный момент на шкале UTC (2024-03-15T07:30:00Z), одинаковый для всех.

LocalDateTime не знает о переводе часов: несуществующее в Берлине время 2024-03-31T02:30 при atZone() молча сдвигается на 03:30+02:00, а в ночь обратного перевода между 00:00 и 06:00 ChronoUnit.HOURS.between насчитает 6 часов вместо реальных 7.

Выбор: LocalDateTime — для локальных значений вроде «приём у врача 15 марта в 10:30», расписаний, поля формы «дата и время»; Instant (или ZonedDateTime/OffsetDateTime) — для меток событий, логов, длительностей и обмена между сервисами.

6. 

Как преобразовать LocalDateTime в Instant или миллисекунды и обратно?

Без зоны преобразование невозможно, поэтому метода toInstant() без аргументов у LocalDateTime нет. Нужно указать зону или смещение:

Instant i1 = ldt.atZone(ZoneId.of("Europe/Moscow")).toInstant();
Instant i2 = ldt.toInstant(ZoneOffset.UTC);
long millis = i1.toEpochMilli();
LocalDateTime back = LocalDateTime.ofInstant(i1, ZoneId.of("Asia/Tokyo"));

Секунды от эпохи даёт ldt.toEpochSecond(ZoneOffset.ofHours(3)), в старый java.util.Date переходят через тот же Instant: Date.from(ldt.atZone(zone).toInstant()).

Осторожно с ZoneId.systemDefault(): на ноутбуке в Москве и на сервере в UTC он даст моменты с разницей в 3 часа. Берите зону пользователя, а если она неизвестна — храните LocalDateTime как есть.

Страница 1 из 1