Дата и время ·
‹ Previous Next ›
⏱ 5 min read Modified: 2026-10-18

Дата и время в Java: java.time API и текущая дата

Попробуйте создать дату 15 февраля 2024 года старым способом: new Date(2024, 1, 15). Код скомпилируется (с предупреждением deprecation), но объект будет хранить 15 февраля 3924 года: к году прибавляется 1900, а месяцы считаются с нуля. В java.time та же дата записывается как LocalDate.of(2024, 2, 15) — и означает ровно то, что написано.

Java Date Time API (пакет java.time, JSR-310) — стандартная библиотека для работы с датой и временем, добавленная в Java 8 на замену java.util.Date и java.util.Calendar. Её основные классы — LocalDate, LocalTime, LocalDateTime, ZonedDateTime, Instant, Period и Duration — неизменяемы (immutable) и потокобезопасны. Текущая дата получается вызовом LocalDate.now(), текущие дата и время — LocalDateTime.now().

Как получить текущую дату и время в Java

Текущую дату и время в Java получают статическим методом now() нужного класса из пакета java.time: LocalDate.now() возвращает только дату, LocalTime.now() — только время, LocalDateTime.now() — дату и время, ZonedDateTime.now() — дату и время с часовым поясом, Instant.now() — момент времени в UTC.

import java.time.Instant;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.ZoneId;
import java.time.ZonedDateTime;

public class CurrentDateTimeExample {
    public static void main(String[] args) {
        LocalDate date = LocalDate.now();               // текущая дата
        LocalTime time = LocalTime.now();               // текущее время
        LocalDateTime dateTime = LocalDateTime.now();   // текущие дата и время
        ZonedDateTime zoned = ZonedDateTime.now();      // + часовой пояс JVM
        Instant instant = Instant.now();                // момент в UTC
        LocalDateTime tokyo = LocalDateTime.now(ZoneId.of("Asia/Tokyo"));

        System.out.println("Дата:        " + date);
        System.out.println("Время:       " + time);
        System.out.println("Дата и время: " + dateTime);
        System.out.println("С поясом:    " + zoned);
        System.out.println("Instant:     " + instant);
        System.out.println("В Токио:     " + tokyo);
    }
}

Пример вывода при запуске 17 октября 2026 года в 14:35 по Москве (Java 17, часовой пояс JVM — Europe/Moscow):

Дата:        2026-10-17
Время:       14:35:07.123456
Дата и время: 2026-10-17T14:35:07.123456
С поясом:    2026-10-17T14:35:07.123456+03:00[Europe/Moscow]
Instant:     2026-10-17T11:35:07.123456Z
В Токио:     2026-10-17T20:35:07.123456

Обратите внимание: Instant всегда печатается в UTC (суффикс Z), поэтому отстаёт от московского времени на 3 часа. Количество знаков после секунд зависит от версии Java и ОС: в Java 8 системные часы дают миллисекунды (14:35:07.123), начиная с Java 9 — обычно микросекунды.

Чтобы вывести текущую дату в привычном формате dd.MM.yyyy, используйте DateTimeFormatter:

String today = LocalDate.now().format(DateTimeFormatter.ofPattern("dd.MM.yyyy"));
System.out.println(today); // Вывод: 17.10.2026

Символы шаблонов и разбор строки в дату — в уроке Класс DateTimeFormatter. Получение отдельно года, месяца и дня недели из текущей даты разобрано в уроке Класс LocalDate.

Классы java.time: какой выбрать

Класс из java.time выбирают по тому, что нужно хранить: дату без времени — LocalDate, время суток — LocalTime, дату и время без пояса — LocalDateTime, дату и время в конкретном поясе — ZonedDateTime, точный момент для логов и БД — Instant, промежуток в днях — Period, в секундах — Duration.

Класс Что хранит Пример toString() Когда использовать
LocalDate Год, месяц, день 2026-10-17 Дата рождения, дата платежа, праздники
LocalTime Часы, минуты, секунды, наносекунды 14:35:07 Время открытия магазина, будильник
LocalDateTime Дата и время без часового пояса 2026-10-17T14:35:07 Время встречи в одном городе, время в чеке
ZonedDateTime Дата, время и часовой пояс (ZoneId) 2026-10-17T14:35:07+03:00[Europe/Moscow] Рейсы, созвоны между странами, переход на летнее время
Instant Секунды и наносекунды от 1970-01-01T00:00:00Z 2026-10-17T11:35:07Z Метки времени в логах, БД, между сервисами
Period Количество лет, месяцев, дней P1Y2M3D Возраст, срок договора, «через 2 месяца»
Duration Секунды и наносекунды PT1H30M Тайм-ауты, длительность операции

Классы, описывающие точку на шкале времени (LocalDate, LocalTime, LocalDateTime, ZonedDateTime, Instant), реализуют интерфейс java.time.temporal.Temporal. Классы-промежутки Period и Duration реализуют java.time.temporal.TemporalAmount — поэтому любой промежуток можно прибавить к дате общим методом plus(TemporalAmount).

Неочевидный момент

Классы с префиксом Local не хранят часовой пояс, но и Instant его не хранит: это просто момент на шкале UTC. Часовой пояс есть только у ZonedDateTime (зона вида Europe/Moscow) и OffsetDateTime (смещение вида +03:00). Получить «местное» время из Instant можно лишь указав зону: instant.atZone(ZoneId.of("Europe/Moscow")).

Чем java.time лучше Date и Calendar

До Java 8 с датами работали через java.util.Date и java.util.Calendar. Эти классы изменяемы и не потокобезопасны, месяцы в них нумеруются с нуля, а некорректные значения молча «перекатываются» в следующий месяц. В java.time все эти проблемы устранены: объекты неизменяемы, месяцы идут с 1, а ошибочная дата сразу вызывает исключение.

Признак Date / Calendar java.time
Изменяемость Изменяемые: setTime(), set(), add() меняют объект Неизменяемые: plusDays() и др. возвращают новый объект
Потокобезопасность Нет; SimpleDateFormat тоже не потокобезопасен Да, включая DateTimeFormatter
Нумерация месяцев С 0: январь = 0, декабрь = 11 С 1, плюс перечисление Month
Год в new Date(y, m, d) Смещение от 1900 (конструктор deprecated) Обычный год: LocalDate.of(2024, 2, 15)
Некорректная дата Молча переносится (29.02.2023 → 01.03.2023) DateTimeException
Часовой пояс Date хранит миллисекунды от эпохи, а при выводе подставляет пояс JVM по умолчанию Есть отдельные классы с поясом и без: LocalDateTime, ZonedDateTime, Instant
Разделение понятий Date одновременно и дата, и время, и момент Отдельный класс на каждую задачу (см. таблицу выше)

Что выведет этот код? Многие ждут исключения, но Calendar по умолчанию работает в «мягком» (lenient) режиме:

import java.time.LocalDate;
import java.util.Calendar;

public class LenientExample {
    public static void main(String[] args) {
        Calendar c = Calendar.getInstance();
        c.clear();
        c.set(2023, Calendar.FEBRUARY, 29);   // 2023 - не високосный год
        System.out.println(c.getTime());
        // Вывод (пояс JVM Europe/Moscow): Wed Mar 01 00:00:00 MSK 2023

        LocalDate date = LocalDate.of(2023, 2, 29);
        // Exception in thread "main" java.time.DateTimeException:
        // Invalid date 'February 29' as '2023' is not a leap year
    }
}

Старый API «исправил» ошибку и выдал 1 марта — такой баг легко пропустить до продакшена. LocalDate.of() сообщает о проблеме сразу, в строке, где она возникла.

Как перейти со старого API: конвертация Date и Calendar

Перевести java.util.Date в классы java.time можно через Instant: date.toInstant(), затем atZone(ZoneId) и toLocalDateTime() или toLocalDate(). Обратно — Date.from(instant). Эти методы появились в Java 8 и нужны, когда библиотека или старый код всё ещё принимает Date.

Из В Как
Date Instant date.toInstant()
Instant Date Date.from(instant)
Date LocalDateTime date.toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime()
LocalDateTime Date Date.from(ldt.atZone(ZoneId.systemDefault()).toInstant())
GregorianCalendar ZonedDateTime calendar.toZonedDateTime() / обратно GregorianCalendar.from(zdt)
java.sql.Date LocalDate sqlDate.toLocalDate() / обратно java.sql.Date.valueOf(localDate)
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.Date;

public class ConvertExample {
    public static void main(String[] args) {
        Date legacy = new Date(0L);                       // 1970-01-01T00:00:00Z
        Instant instant = legacy.toInstant();
        LocalDateTime moscow = instant.atZone(ZoneId.of("Europe/Moscow"))
                                      .toLocalDateTime();
        Date back = Date.from(instant);

        System.out.println(instant);                    // Вывод: 1970-01-01T00:00:00Z
        System.out.println(moscow);                     // Вывод: 1970-01-01T03:00
        System.out.println(back.getTime());             // Вывод: 0
    }
}

На чём чаще всего ошибаются

Самая частая ошибка новичков в java.time — вызвать plusDays() или withYear() и не сохранить результат: объект неизменяем, и исходная дата остаётся прежней. Кроме того, неожиданности дают сложение месяцев в конце месяца и сокращённый вывод toString().

import java.time.LocalDate;
import java.time.LocalTime;

public class MistakesExample {
    public static void main(String[] args) {
        LocalDate date = LocalDate.of(2024, 1, 31);
        date.plusDays(1);                          // результат потерян
        System.out.println(date);                  // Вывод: 2024-01-31

        date = date.plusDays(1);                   // правильно
        System.out.println(date);                  // Вывод: 2024-02-01

        LocalDate endOfJan = LocalDate.of(2024, 1, 31);
        System.out.println(endOfJan.plusMonths(1)); // Вывод: 2024-02-29

        System.out.println(LocalTime.of(14, 0));    // Вывод: 14:00
        System.out.println(LocalTime.of(14, 0, 5)); // Вывод: 14:00:05
    }
}
  • Потерянный результат. Методы plus*(), minus*(), with*() возвращают новый объект — присваивайте его переменной.
  • Конец месяца. plusMonths(1) от 31 января даёт последний существующий день февраля (29-е в високосном 2024 году), а не 2 или 3 марта.
  • Короткий toString(). Нулевые секунды и наносекунды не печатаются, поэтому LocalTime.of(14, 0) выводится как 14:00. Для стабильного формата (отчёты, сравнение строк) используйте DateTimeFormatter.
  • LocalDateTime для меток событий. Без пояса нельзя понять, когда событие произошло на самом деле, если серверы стоят в разных зонах. Для логов и БД храните Instant.

Презентация и видео на Patreon →

Часто задаваемые вопросы

Почему LocalDateTime.now() на сервере показывает не то время, что на моём компьютере?

Методы now() без аргументов берут часовой пояс JVM по умолчанию (ZoneId.systemDefault()), а он берётся из настроек ОС сервера. Если сервер работает в UTC, а вы в Москве, разница составит 3 часа. Передавайте зону явно — LocalDateTime.now(ZoneId.of("Europe/Moscow")), задайте параметр JVM -Duser.timezone=Europe/Moscow или храните моменты в Instant и переводите в нужную зону только при выводе.

Чем Instant.now() отличается от System.currentTimeMillis()?

Оба возвращают текущий момент относительно эпохи 1970-01-01T00:00:00Z. System.currentTimeMillis() отдаёт long в миллисекундах, а Instant.now() — объект с секундами и наносекундами, который можно сравнивать, складывать с Duration и переводить в ZonedDateTime. Для замера длительности выполнения кода берите System.nanoTime(): он не зависит от перевода системных часов.

Как подменить текущую дату в unit-тестах?

У каждого метода now() есть перегрузка now(Clock). В рабочем коде передавайте Clock.systemDefaultZone(), а в тесте — Clock.fixed(Instant.parse("2024-02-29T10:00:00Z"), ZoneOffset.UTC). Тогда LocalDate.now(clock) всегда вернёт 2024-02-29, и тест не зависит от дня запуска.

Нужно ли переписывать старый код с java.util.Date на java.time?

Срочно — нет: класс Date не удалён, устаревшими помечены только его конструкторы и методы с годом, месяцем и днём. В новом коде используйте java.time, а на границе со старым API конвертируйте значения — таблица методов в разделе Как перейти со старого API. JDBC 4.2 и Hibernate 5+ работают с LocalDate, LocalDateTime и Instant напрямую.

Video Explanation

Prefer video format? Watch this lesson with examples and explanations.

Comments

Please log in or register to have a possibility to add comment.