1. Вступ до Date Time API

Вступ до Date Time API

Створювачам Java не дуже подобалася поточна ситуація з класами Date і Calendar. Вони були хороші свого часу, але часи змінюються. Потрібно було щось просте, потужне та надійне. І ось одночасно з випуском Java 8 (через 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, чиї методи ми викликаємо, не змінюється. Натомість його методи повертають об'єкти, які й містять потрібні дані.