1. Введение в Date Time API

Введение в Date Time API

Создателям Java не сильно нравилась текущая ситуация с классами Date и Calendar. Они были хороши в свое время, но времена меняются. И нужно было что-то простое, мощное и надежное. И вот вместе с выходом Java8 (15 лет спустя после выхода Calendar) был представлен Java Date Time API: набор классов, которые должны решить все возможные проблемы со временем.

Классов было так много, что их решили разнести по нескольким пакетам:

Пакет java.time — базовый пакет для Java Date Time API: в нем содержатся такие классы как LocalDate, LocalTime, LocalDateTime, Instant, Period, Duration. Все объекты этих классов — immutable: их нельзя изменить после создания.

Пакет java.time.format содержит в себе классы для форматирования времени: преобразования времени (и даты) в текстовую строку и обратно. Например, в нем содержится такой универсальный класс как DateTimeFormatter, который пришел на смену SimpleDateFormat.

Пакет java.time.zone содержит классы для работы с часовыми поясами (time zones). Он содержит такие классы как TimeZone и ZonedDateTime. Если вы пишете код для сервера, клиенты которого находятся в разных частях света, эти классы вам очень понадобятся.


2. Класс LocalDate

Первый и самый полезный класс из Date Time API, который мы изучим — это класс LocalDate. Как вы, скорее всего, догадываетесь по его названию, этот класс создан для работы с датой.

Объекты этого класса не изменяются после создания (класс LocalDate immutable). Зато это добавило классу простоты и надежности. Особенно если с объектом класса одновременно взаимодействуют несколько нитей (потоков исполнения).

Чтобы создать новый объект класса LocalDate, нужно использовать один из статических методов. Вот список основных.

Получение текущей даты

Чтобы получить текущую дату, нужно воспользоваться статическим методом now(). Это гораздо проще, чем кажется:

LocalDate today = LocalDate.now();

Где today — это переменная класса LocalDate, а LocalDate.now() — вызов статического метода now() у класса LocalDate.

Пример:

Код Вывод на экран
LocalDate today = LocalDate.now();
System.out.println("Сегодня = " + today);

Сегодня = 2019-02-22

Получение даты в определенном часовом поясе

Также у класса LocalDate есть разновидность метода now(ZoneId), который позволяет получить текущую дату в определенном часовом поясе.

Для этого нам понадобится еще один класс — ZoneId (java.time.ZoneId). У него есть метод of(), который возвращает объект ZoneId по имени часового пояса.

Чтобы определить текущую дату в Шанхае, нужно написать код:

Код Вывод на экран
ZoneId  timezone = ZoneId.of("Asia/Shanghai");
LocalDate today = LocalDate.now(timezone);
System.out.println("Сейчас в Шанхае = " + today);


Сейчас в Шанхае = 2019-02-22

Список имен всех часовых поясов (time zone) можно найти в интернете.


3. Получение конкретной даты

Чтобы получить объект LocalDate, содержащий определенную дату, нужно воспользоваться статическим методом of(). Выглядит все тоже очень просто и понятно:

LocalDate date = LocalDate.of(2019, Month.FEBRUARY, 22);

Где date — это переменная класса LocalDate, а LocalDate.of() — вызов статического метода of() у класса LocalDate.

Также тут мы видим использование специальной константы FEBRUARY класса Month (java.time.Month) для задания месяца Февраль.

Можно задать месяц и по старинке — с помощью числа:

LocalDate date = LocalDate.of(2019, 2, 22);

Двойка? Вместо месяца Февраль? Это что, месяцы теперь опять нумеруются с единицы?

Да, наконец-то спустя почти 20 лет после создания Java месяцы перестали нумеровать с нуля.

Пример:

Код Вывод на экран
LocalDate today = LocalDate.of(2019, 2, 22);
System.out.println("Сегодня = " + today);

Сегодня = 2019-02-22

Получение даты по номеру дня

Есть еще один любопытный метод создания даты: с помощью метода ofYearDay можно получить дату, имея только номер года и номер дня года. Общий вид такой:

LocalDate date = LocalDate.ofYearDay(год, день);

Где год — это номер года, а день — номер дня в году.

Пример:

Код Вывод на экран
LocalDate today = LocalDate.ofYearDay(2019, 100);
System.out.println("Сегодня = " + today);

Сегодня = 2019-04-10

Сотый день в 2019 году — это 10 апреля.

Получение даты Unix

Помните, что объекты класса Date всегда хранили время в миллисекундах с 1 января 1970 года? Чтобы программисты не скучали по старым добрым временам, в класс LocalDate добавили метод ofEpochDay(), который возвращает дату, отсчитанную от 1 января 1970 года. Общий вид такой:

LocalDate date = LocalDate.ofEpochDay(день);

Где день — это количество дней, прошедшее с 1 января 1970 года.

Пример:

Код Вывод на экран
LocalDate today = LocalDate.ofEpochDay(1);
System.out.println("Сегодня = " + today);

Сегодня = 1970-01-02

4. Получение фрагментов даты

Изменять объекты класса LocalDate нельзя, а вот получать отдельные фрагменты даты еще как можно. Для этого у объектов класса LocalDate есть несколько методов:

Метод Описание
int getYear()
Возвращает год из конкретной даты
Month getMonth()
Возвращает месяц даты — одну из специальных констант
JANUARY, FEBRUARY, ...;
int getMonthValue()
Возвращает номер месяца из даты. Январь == 1.
int getDayOfMonth()
Возвращает номер дня в месяце
int getDayOfYear()
Возвращает номер дня с начала года
DayOfWeek getDayOfWeek()
Возвращает день недели: одну из специальных констант
MONDAY, TUESDAY, ...;
IsoEra getEra()
Возвращает эру: константа BC (Before Current Era) и CE(Current Era)

Пример:

Код Вывод на экран
LocalDate today = LocalDate.now();
System.out.println(today.getYear());
System.out.println(today.getMonth());
System.out.println(today.getMonthValue());
System.out.println(today.getDayOfMonth());
System.out.println(today.getDayOfWeek());

2019
FEBRUARY
2
22
FRIDAY

5. Изменение даты в объекте LocalDate

Класс LocalDate содержит несколько методов, которые позволяют работать с датой. Эти методы реализованы по аналогии с методами класса String: каждый из этих методов не меняет существующий объект LocalDate, а возвращает новый с нужными данными.

Вот какие методы есть у класса LocalDate:

Метод Описание
plusDays(int days)
Добавляет определенное количество дней к дате
plusWeeks(int weeks)
Добавляет недели к дате
plusMonths(int months)
Добавляет месяцы к дате
plusYears(int years)
Добавляет годы к дате
minusDays(int days)
Отнимает дни от даты
minusWeeks(int weeks)
Отнимает недели от даты
minusMonths(int months)
Отнимает месяцы от даты
minusYears(int years)
Отнимает годы от даты

Пример:

Код Вывод на экран
LocalDate birthday = LocalDate.of(2019, 2, 28);
LocalDate nextBirthday = birthday.plusYears(1);
LocalDate firstBirthday = birthday.minusYears(30);

System.out.println(birthday);
System.out.println(nextBirthday);
System.out.println(firstBirthday);




2019-02-28
2020-02-28
1989-02-28

Объект birthday, чьи методы мы вызываем, не меняется. Вместо этого его методы возвращают новые объекты, которые и содержат нужные данные.