Класс LocalDateTime в Java: создание, форматирование и примеры - Вопросы
Всего: 6 вопросов
1. Что такое LocalDateTime в Java и как создать объект этого класса?
Что такое 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 в своём формате?
Почему 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?
Как изменить и сравнить значения 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?
Как посчитать разницу между двумя 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 отличается от 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 или миллисекунды и обратно?
Как преобразовать 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 как есть.