1. Перехід від класу Date до класу Calendar

Перехід від класу Date до класу Calendar

Програмісти любили клас Date за його простоту й за підтримку стандартів Unix, але, як відомо, наші недоліки — це продовження наших чеснот.

Програмісти хотіли мати «розумний клас Date». І такий клас з'явився — ним став клас Calendar. Його задумували як інструмент не лише для зберігання дат, а й для складної роботи з ними.

Повне ім'я класу Calendar — java.util.Calendar. Не забувайте додавати його в import, якщо вирішите використовувати у своєму коді.

Створити об'єкт Calendar можна за допомогою команди:

Calendar date = Calendar.getInstance();

Статичний метод getInstance() класу Calendar створить об'єкт Calendar, ініціалізований поточною датою. Залежно від налаштувань комп'ютера, на якому виконується програма, буде створено потрібний календар.

Правильніше було б сказати «актуальний». Річ у тім, що на Землі не один календар, а багато. І майже кожен із них пов'язаний з якоюсь релігією або країною. Клас Calendar підтримує три календарі:

Календар Опис
GregorianCalendar Християнський григоріанський календар
BuddhistCalendar Буддистський календар
JapaneseImperialCalendar Японський імператорський календар

А ще ж є китайський та арабський календарі. Загалом, працювати з часом не так просто, як здається.

У Китаї на момент написання цієї лекції офіційно 4716 рік. А за мусульманським календарем — 1398. Ласкаво просимо у великий світ, друже-програмісте!

2. Створення об'єкта-календаря

Ми будемо використовувати григоріанський календар, як найпоширеніший у світі. Принаймні доти, доки Китай не купить компанію Oracle і не зробить свій календар основним.

Об'єкт-календар із довільною датою створюють за допомогою команди

Calendar date = new GregorianCalendar(рік, місяць, день);

Так, щоразу доведеться писати GregorianCalendar. Можна і замість Calendar писати GregorianCalendar: так теж працюватиме. Просто Calendar писати швидше.

Рік потрібно писати повністю: ніяких 19 замість 2019. Місяці, як і раніше, нумеруються з нуля. А дні місяця, як і раніше, нумеруються не з нуля (слабаки!).

Щоб задати не тільки дату, а й час, слід передати його як додаткові параметри:

… = new GregorianCalendar(рік, місяць, день, години, хвилини, секунди);

Можна передати навіть мілісекунди, якщо є потреба: їх указують як наступний параметр після секунд.

3. Виведення об'єкта-календаря на екран

Якщо просто вивести об'єкт-календар на екран, результат вас не дуже порадує.

Код
Calendar calendar = new GregorianCalendar(2019, 03, 12);
System.out.println(calendar);
Виведення на екран
java.util.GregorianCalendar[time=?,areFieldsSet=false,areAllFieldsSet=false,lenient=true,zone=sun.util.calendar.ZoneInfo[id="Europe/Helsinki",offset=7200000,dstSavings=3600000,useDaylight=true,transitions=118,lastRule=java.util.SimpleTimeZone[id=Europe/Helsinki,offset=7200000,dstSavings=3600000,useDaylight=true,startYear=0,startMode=2,startMonth=2,startDay=-1,startDayOfWeek=1,startTime=3600000,startTimeMode=2,endMode=2,endMonth=9,endDay=-1,endDayOfWeek=1,endTime=3600000,endTimeMode=2]],firstDayOfWeek=1,minimalDaysInFirstWeek=1,ERA=?,YEAR=2019,MONTH=3,WEEK_OF_YEAR=?,WEEK_OF_MONTH=?,DAY_OF_MONTH=12,DAY_OF_YEAR=?,DAY_OF_WEEK=?,DAY_OF_WEEK_IN_MONTH=?,AM_PM=0,HOUR=0,HOUR_OF_DAY=0,MINUTE=0,SECOND=0,MILLISECOND=?,ZONE_OFFSET=?,DST_OFFSET=?]

Уся річ у тім, що календар — це саме календар, а не дата: у нього багато різних параметрів, і всі вони виводяться на екран.

Правильно буде відображати об'єкт календар за допомогою класу SimpleDateFormat, але поки ми його не вивчили, можна скористатися лайфхаком.

Date date = calendar.getTime();

Просто об'єкт типу Calendar можна легко перетворити на об'єкт типу Date, а як виводити на екран об'єкт типу Date, ви вже знаєте. Приблизно так можна перетворити об'єкт Calendar на Date:

Використання методу getTime():

Код Виведення на екран
Calendar calendar = new GregorianCalendar(2019, 03, 12);
System.out.println(calendar.getTime());
 Fri Apr 12 00:00:00 EEST 2019

Зовсім інша справа, чи не так?

4. Робота з фрагментами дати

Для отримання фрагменту дати (рік, місяць, …) клас Calendar має спеціальний метод — get(). Метод один, зате з параметрами:

int month = calendar.get(Calendar.MONTH);

де calendar — це змінна типу Calendar, а MONTH — це змінна-константа класу Calendar.

У метод get ви передаєте як параметр спеціальну константу класу Calendar і в результаті отримуєте потрібне значення.

Приклади

Код Опис
Calendar calendar = Calendar.getInstance();

int era = calendar.get(Calendar.ERA);
int year = calendar.get(Calendar.YEAR);
int month = calendar.get(Calendar.MONTH);
int day = calendar.get(Calendar.DAY_OF_MONTH);

int dayOfWeek = calendar.get(Calendar.DAY_OF_WEEK);
int hour = calendar.get(Calendar.HOUR);
int minute = calendar.get(Calendar.MINUTE);
int second = calendar.get(Calendar.SECOND);


ера (до нашої ери чи після)
рік
місяць
день місяця

день тижня
години
хвилини
секунди

Для змінення фрагмента дати використовується метод set:

calendar.set(Calendar.MONTH, значення);

де calendar — це змінна типу Calendar, а MONTH — це змінна-константа класу Calendar.

У метод set ви передаєте як перший параметр спеціальну константу класу Calendar, а як другий параметр — нове значення.

Приклади

Код Опис
Calendar calendar = new GregorianCalendar();

calendar.set(Calendar.YEAR, 2019);
calendar.set(Calendar.MONTH, 6);
calendar.set(Calendar.DAY_OF_MONTH, 4);
calendar.set(Calendar.HOUR_OF_DAY, 12);
calendar.set(Calendar.MINUTE, 15);
calendar.set(Calendar.SECOND, 0);

System.out.println(calendar.getTime());


рік = 2019
місяць = липень (нумерація з 0)
4 число
години
хвилини
секунди

5. Константи класу Calendar

У класі Calendar є константи не лише для назв фрагментів дати, а й, мабуть, на всі випадки життя.

Calendar date = new GregorianCalendar(2019, Calendar.JANUARY, 31);

Наприклад, є константи для позначення місяців:

Або, приміром, для днів тижня:

Calendar calendar = new GregorianCalendar(2019, Calendar.JANUARY, 31);
if (calendar.get(Calendar.DAY_OF_WEEK) == Calendar.FRIDAY)
{
   System.out.println("Це п'ятниця");
}

Усе перелічувати не будемо. Просто не дивуйтеся, якщо побачите такі записи в коді.

Використання констант дає змогу зробити код читабельнішим, тому програмісти їх і додали. Ну а місяці нумеруються з нуля теж заради легкочитності. Або ні.

6. Змінення дати в об'єкті Calendar

Клас Calendar має метод, який дає змогу виконувати з датою розумніші операції, як-от додати до неї рік, місяць або кілька днів. Або відняти. Цей метод називається add(). Працювати з ним можна приблизно так:

calendar.add(Calendar.MONTH, значення);

де calendar — це змінна типу Calendar, а MONTH — це змінна-константа класу Calendar.

У метод add ви передаєте як перший параметр спеціальну константу класу Calendar, а як другий параметр — значення, яке треба додати.

Особливість цього методу в тому, що він розумний. Подивіться самі наскільки:

Код
Calendar calendar = new GregorianCalendar(2019, Calendar.FEBRUARY, 27);
calendar.add(Calendar.DAY_OF_MONTH, 2);
System.out.println(calendar.getTime());
Виведення на екран
Fri Mar 01 00:00:00 EET 2019

Цей метод розуміє, що в лютому 2019 року лише 28 днів і підсумкова дата — 1 березня.

А тепер віднімемо 2 місяці! Що має вийти? 27 грудня 2018 року! Зараз перевіримо.

Щоб виконати дію, яка зменшує дату, потрібно в метод add() передати значення зі знаком «−»:

Код
Calendar calendar = new GregorianCalendar(2019, Calendar.FEBRUARY, 27);
calendar.add(Calendar.MONTH, -2);
System.out.println(calendar.getTime());
Виведення на екран
Thu Dec 27 00:00:00 EET 2018

Працює!

Цей метод ураховує кількість днів у місяцях і високосні роки. Тобто метод чудовий. Саме те, що потрібно більшості програмістів, які багато працюють із датами.

7. Прокручування фрагментів дати

Однак іноді трапляються ситуації, коли така розумна поведінка зайва: хочеться щось зробити з однією частиною дати, не змінюючи все інше.

Для цього клас Calendar має спеціальний метод — roll(). За своєю сигнатурою він повністю аналогічний методу add(), але будь-які зміни з його допомогою стосуються одного параметра, решта залишаються незмінними.

Приклад:

Код
Calendar calendar = new GregorianCalendar(2019, Calendar.FEBRUARY, 27);
calendar.roll(Calendar.MONTH, -2);
System.out.println(calendar.getTime());
Виведення на екран
Fri Dec 27 00:00:00 EET 2019

Місяць ми змінили, а рік і число залишилися без змін.