1. Класс ZonedDateTime

Есть еще один очень интересный класс в Date Time API — класс ZonedDateTime. Основное его назначение — удобно работать с датами в разных часовых поясах.

LocalDate отлично подходит для описания дат. Например, дня рождения: у меня день рождения 15 марта независимо от того, где я нахожусь. Это пример даты.

LocalTime отлично подходит для описания времени, например, будильника: я завел будильник на 5 утра и все равно, где я нахожусь. 5 утра — это 5 утра. Это пример работы с временем.

А теперь допустим, что мы пишем приложение, которое бронирует авиабилеты. Самолеты взлетают и прилетают по местному времени, самолет летит фиксированное время, но часовые пояса меняются.

Временные зоны

Кстати, с временными зонами (часовыми поясами) в мире настоящий бардак. Более того, если вы думаете, что часовых поясов 24, вы сильно ошибаетесь.

Например, время в Индии отличается от Гринвича на 5 c половиной часов: GMT+5:30. Одни страны переходят на летнее время, другие нет. Причем разные страны переходят на летнее время в разное время года.

А некоторые страны с помощью законов отменяют переход на летнее время, или снова вводят, или опять отменяют.

В общем, в мире есть временные зоны, внутри каждой зоны одно время. Время в разных зонах может совпадать в определенные периоды года, а в другие периоды отличаться. Зоны обычно называют по крупным городам, находящимся в них: Europe/Monaco, Asia/Singapore, хотя бывают и исключения — US/Pacific.

Всего в настоящий момент официально известно 599 временных зон. Вдумайтесь: 599. Это совсем не 24. Добро пожаловать в глобальный мир.

Для хранения временной зоны в Java используется класс ZoneId из пакета java.time.

Кстати, у него есть статический метод getAvailableZoneIds(), который возвращает множество всех известных на текущий момент временных зон. Чтобы получить список всех зон, нужно написать такой код:

Код Вывод на экран (часть)
for (String s: ZoneId.getAvailableZoneIds())
   System.out.println(s);
Asia/Aden
America/Cuiaba
Etc/GMT+9
Etc/GMT+8

Чтобы получить объект ZoneId по его имени, нужно воспользоваться статическим методом of();

Код Примечание
ZoneId zone = ZoneId.of("Africa/Cairo");
Каир


2. Создание объекта ZonedDateTime

При создании объекта ZonedDateTime нужно вызвать у него статический метод now() и передать в него объект ZoneId.

Код Вывод на экран
ZoneId zone = ZoneId.of("Africa/Cairo");
ZonedDateTime time = ZonedDateTime.now(zone);
System.out.println(time);


2019-02-22T11:37:58.074816+02:00[Africa/Cairo]

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

Пример:

Код Вывод на экран
ZonedDateTime time = ZonedDateTime.now();
System.out.println(time);

2019-02-22T13:39:05.70842+02:00[Europe/Helsinki]

Преобразование глобальной даты в локальную

Одной из интересных особенностей ZonedDateTime является возможность его преобразования в локальную дату и время. Пример.

ZoneId zone = ZoneId.of("Africa/Cairo");
ZonedDateTime cairoTime = ZonedDateTime.now(zone);

LocalDate localDate = cairoTime.toLocalDate();
LocalTime localTime = cairoTime.toLocalTime();
LocalDateTime localDateTime = cairoTime.toLocalDateTime();

3. Работа со временем

Как и у класса LocalDateTime, у класса ZonedDateTime есть много способов получить отдельные фрагменты даты и времени. Вот список этих методов:

int getYear()
Возвращает год из конкретной даты
Month getMonth()
Возвращает месяц даты: одну из специальных констант JANUARY, FEBRUARY, ...;
int getMonthValue()
Возвращает номер месяца из даты. Январь == 1
int getDayOfMonth()
Возвращает номер дня в месяце
DayOfWeek getDayOfWeek()
Возвращает день недели: одну из специальных констант MONDAY, TUESDAY, ...;
int getDayOfYear()
Возвращает номер дня в году
int getHour()
Возвращает часы
int getMinute()
Возвращает минуты
int getSecond()
Возвращает секунды
int getNano()
Возвращает наносекунды

Все методы полностью аналогичны методам LocalDateTime. И, конечно, у класса ZonedDateTime есть методы, которые позволяют работать с датой и временем. При этом объект, у которого вызываются методы, не меняется: вместо этого методы возвращают новый объект ZonedDateTime:

Методы Описание
plusYears(int)
Добавляет годы к дате
plusMonths(int)
Добавляет месяцы к дате
plusDays(int)
Добавляет дни к дате
plusHours(int)
Добавляет часы
plusMinutes(int)
Добавляет минуты
plusSeconds(int)
Добавляет секунды
plusNanos(int)
Добавляет наносекунды
minusYears(int)
Отнимает годы от даты
minusMonths(int)
Отнимает месяцы от даты
minusDays(int)
Отнимает дни от даты
minusHours(int)
Вычитает часы
minusMinutes(int)
Вычитает минуты
minusSeconds(int)
Вычитает секунды
minusNanos(int)
Вычитает наносекунды

Примеры приводить не будем: думаем, тут и так все понятно по аналогии с только что рассмотренными классами.