Що таке дата, думаю, пояснювати не потрібно:) В принципі, записати поточну дату і час у Java цілком можливо у звичайний рядок.
public class Main {
public static void main(String[] args) {
String date = "11 червня 2018 року";
System.out.println(date);
}
} Але такий підхід має багато недоліків. Клас Stringстворено до роботи з текстом, і методи в нього відповідні. Якщо нам потрібно буде якось керувати датою (додати до неї 2 години, наприклад), Stringтут не впорається. Або, наприклад, вивести в консоль поточну дату та час на момент компіляції програми. Тут Stringтеж не допоможе: поки ти напишеш код і запустиш його - час зміниться і консоль буде виведено неактуальне. Тому Java його творцями були передбачені кілька класів до роботи з датами і часом. Перший з них – це класjava.util.Date
Клас Date Java
Ми вказали для нього повну назву, оскільки в іншому пакеті Java є ще класjava.sql.Date. Не переплутай! Перше, що потрібно про нього знати, він зберігає дату в мілісекундах , які пройшли з 1 січня 1970 року. Для цієї дати є навіть окрема назва - "Unix-час" Досить цікавий спосіб, згоден? :) Друге, що варто запам'ятати: якщо створити об'єкт Dateз порожнім конструктором - результатом буде поточна дата і час на момент створення об'єкта . Пам'ятаєш, ми писали, що для дати у форматі Stringтаке завдання буде проблематичним? Клас Dateїї легко вирішує.
public class Main {
public static void main(String[] args) {
Date date = new Date();
System.out.println(date);
}
} Запусти цей код кілька разів, і побачиш, як час щоразу змінюватиметься:) Це можливо саме завдяки зберіганню в мілісекундах: вони є найменшою одиницею часу, тому результати настільки точні. Існує й інший конструктор для Date: можна вказати точну кількість мілісекунд, яка пройшла з 00:00 1 січня 1970 до необхідної дати, і вона буде створена:
public class Main {
public static void main(String[] args) {
Date date = new Date(1212121212121L);
System.out.println(date);
}
} Виведення в консоль:
Fri May 30 08:20:12 MSD 2008 В нас вийшло 30 травня 2008 року. "Fri" означає день тижня - "Friday" (п'ятниця), а MSD - "Moscow Daylight Saving" (московський літній час). Мілісекунди передаються у форматі long, оскільки їх кількість найчастіше не влазить у int. Отже, які операції з датами нам можуть знадобитися у роботі? Ну, найочевидніше, звісно — порівняння . Визначити чи була одна дата пізніше чи раніше за іншу. Це можна зробити по-різному. Наприклад, можна викликати метод Date.getTime(). Він поверне кількість мілісекунд, що пройшли з півночі 1 січня 1970 року. Просто викличемо його у двох об'єктів Date і порівняємо між собою:
public class Main {
public static void main(String[] args) {
Date date1 = new Date();
Date date2 = new Date();
System.out.println((date1.getTime() > date2.getTime())?
"date1 пізніше date2" : "date1 раніше date2");
}
} Висновок:
date1 раньше date2 Але є й зручніший спосіб, саме — використовувати спеціальні методи класу Date: before(), after()і equals(). Усі вони повертають результат у форматі boolean. Метод before()перевіряє, чи була наша дата раніше тієї, яку ми передаємо як аргумент:
public class Main {
public static void main(String[] args) throws InterruptedException {
Date date1 = new Date();
Thread.sleep(2000);//припинимо роботу програми на 2 секунди
Date date2 = new Date();
System.out.println(date1.before(date2));
}
} Виведення в консоль:
true Схожим чином працює і метод after(), він перевіряє, чи була наша дата пізніше тієї, яку ми передаємо як аргумент:
public class Main {
public static void main(String[] args) throws InterruptedException {
Date date1 = new Date();
Thread.sleep(2000);//припинимо роботу програми на 2 секунди
Date date2 = new Date();
System.out.println(date1.after(date2));
}
} Виведення в консоль:
false У прикладах ми “присипляємо” програму на 2 секунди, щоб дві дати гарантовано відрізнялися. На швидких комп'ютерах час між створенням date1і date2може бути меншим за одну мілісекунду, і в такому випадку обидва методи — і before(), і after()— повертатимуть false. А ось метод equals()у такій ситуації поверне true! Адже він порівнює саме кількість мілісекунд, що пройшли з 00:00 1 січня 1970 року для кожної дати. Об'єкти вважатимуться рівними тільки в тому випадку, якщо збігаються аж до мілісекунди:
public static void main(String[] args) {
Date date1 = new Date();
Date date2 = new Date();
System.out.println(date1.getTime());
System.out.println(date2.getTime());
System.out.println(date1.equals(date2));
} Ось ще на що треба звернути увагу. Якщо ти відкриєш документацію класу Dateна сайті Oracle, то побачиш, що багато його методів та конструкторів були позначені словом Deprecated(“нерекомендований”). Ось, подивися: Class Date Ось що самі творці Java говорять про ті частини класів, які стали deprecated: “Програмний елемент, анотований @Deprecated, є тим, що програмістам не рекомендується використовувати, як правило, тому, що це небезпечно, або тому, що є найкраща альтернатива.” Не означає, що цими методами взагалі не можна користуватися. Більше того, якщо ти сам спробуєш запустити код з їх використанням в IDEA - він, швидше за все, буде працювати Візьмемо для прикладу deprecated методDate.getHours(), який повертає кількість годинників з об'єкта Date.
public static void main(String[] args) {
Date date1 = new Date();
System.out.println(date1.getHours());
} Якщо на момент запуску коду у вас, наприклад, час 14:21 він виведе число 14. Як бачите, deprecated-метод закреслено, але він цілком собі працює. Це методи не стали прибирати зовсім, щоб не зламати купу вже написаного з використанням коду. Тобто ці методи не "зламані" і не "віддалені", просто їх не рекомендують використовувати через наявність більш зручної альтернативи. Про неї, до речі, написано прямо в документації:
Більшість методів класу Date було перенесено до його покращеної, розширеної версії — класу Calendar. З ним ми й познайомимося далі:)
Java Calendar
У версії Java 1.1 з'явився новий класCalendar. Він зробив роботу з дат в Java дещо простіше, ніж вона виглядала раніше. Єдиною реалізацією класу Calendar, з якою ми і працюватимемо, є клас GregorianCalendar(він реалізує Григоріанський календар, за яким живе більшість країн світу). Його основна зручність полягає в тому, що він вміє працювати з датами у зручнішому форматі. Наприклад, він може:
- Додати до поточної дати місяць або день
- Перевірити, чи рік високосним;
- Отримати окремі компоненти дати (наприклад, одержати з цілої дати номер місяця)
- А також усередині нього розроблена дуже зручна система констант (багато з них ми побачимо нижче).
Calendarє те, що в ньому реалізована константа Calendar.Era: ти можеш встановити для дати еру BC ("Before Christ" - до Різдва Христового, тобто "до нашої ери") або AC ("After Christ" - " Наша ера"). Давайте розглянемо все це на прикладах. Створимо календар із датою 25 січня 2017 року:
public static void main(String[] args) {
Calendar calendar = new GregorianCalendar(2017, 0 , 25);
} Місяці в класі Calendar(як і в Date, до речі) починаються з нуля, тому ми передали число 0 як другий аргумент. Головне при роботі з класом Calendar— розуміти, що це календар , а не окрема дата.
Дата — це кілька чисел, що позначають конкретний проміжок часу. А календар - це цілий пристрій, за допомогою якого можна багато чого робити з датами:) Це досить добре видно, якщо спробувати вивести об'єкт Calendar в консоль: Висновок:
java.util.GregorianCalendar[time=?,areFieldsSet=false,areAllFieldsSet=false,lenient=true,zone=sun.util.calendar.ZoneInfo[id="Europe/Moscow",offset=10800000,dstSavings=0,useDaylight=false,transitions=79,lastRule=null],firstDayOfWeek=2,minimalDaysInFirstWeek=1,ERA=?,YEAR=2017,MONTH=0,WEEK_OF_YEAR=?,WEEK_OF_MONTH=?,DAY_OF_MONTH=25,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=?] Бачиш, скільки інформації! У календаря є купа властивостей, які не має звичайна дата, і всі вони виводяться в консоль (так працює метод toString()у класі Calendar). Якщо під час роботи тобі потрібно отримати з календаря просту дату, тобто. об'єкт Date— це робиться за допомогою методу Calendar.getTime()(назва не логічна, але тут вже нічого не поробиш):
public static void main(String[] args) {
Calendar calendar = new GregorianCalendar(2017, 0 , 25);
Date date = calendar.getTime();
System.out.println(date);
} Висновок:
Wed Jan 25 00:00:00 MSK 2017 Ось тепер ми спростабо календар до звичайної дати. Поїхали далі. Крім цифрових позначень місяців у класі Calendarможна використовувати константи. Константи - це статичні поля класу Calendarз встановленим значенням, яке не можна змінити. Цей варіант насправді навіть кращий, оскільки таке написання покращує читання коду.
public static void main(String[] args) {
GregorianCalendar calendar = new GregorianCalendar(2017, Calendar.JANUARY , 25);
}Calendar.JANUARY- Одна з констант для позначення місяця. При такому варіанті іменування ніхто не забуде, наприклад, що цифра "3" означає квітень, а не звичний нам третій місяць - березень. Просто пишеш Calendar.APRIL- і все:) Усі поля календаря (число, місяць, хвабони, секунди тощо) можна встановлювати окремо за допомогою методу set(). Він дуже зручний, оскільки в класі Calendarдля кожного поля виділено свою константу, і підсумковий код буде виглядати максимально просто. Наприклад, у минулому прикладі ми створабо дату, але не встановабо для неї поточний час. Давай встановимо час 19:42:12
public static void main(String[] args) {
Calendar calendar = new GregorianCalendar();
calendar.set(Calendar.YEAR, 2017);
calendar.set(Calendar.MONTH, 0);
calendar.set(Calendar.DAY_OF_MONTH, 25);
calendar.set(Calendar.HOUR_OF_DAY, 19);
calendar.set(Calendar.MINUTE, 42);
calendar.set(Calendar.SECOND, 12);
System.out.println(calendar.getTime());
} Висновок:
Wed Jan 25 19:42:12 MSK 2017 Ми викликаємо метод set(), передаємо до нього константу (залежно від того поля, яке хочемо змінити) та нове значення для цього поля. Виходить, що метод set()- такий собі "супер-сеттер", який вміє встановлювати значення не для одного поля, а для безлічі полів:) Додавання та віднімання значень у класі Calendarздійснюється за допомогою методу add(). У нього необхідно передати те поле, яке ти хочеш змінити, і число - скільки саме ти хочеш додати/зменшити від поточного значення. Наприклад, повернемо дату, яку ми створабо, на 2 місяці тому:
public static void main(String[] args) {
Calendar calendar = new GregorianCalendar(2017, Calendar.JANUARY , 25);
calendar.set(Calendar.HOUR, 19);
calendar.set(Calendar.MINUTE, 42);
calendar.set(Calendar.SECOND, 12);
calendar.add(Calendar.MONTH, -2);//щоб відібрати значення - метод потрібно передати негативне число
System.out.println(calendar.getTime());
} Висновок:
Fri Nov 25 19:42:12 MSK 2016 Чудово! Ми повернули дату на 2 місяці тому. В результаті змінився не лише місяць, а й рік, з 2017 на 2016 рік. Підрахунок поточного року при перенесенні дат, звичайно, виконується автоматично і його не треба контролювати вручну. Але якщо для якихось цілей тобі потрібно відключити цю поведінку, то можна й так. Спеціальний метод roll()може додавати й зменшувати значення, не торкаючись у своїй інші значення. Наприклад, ось так:
public static void main(String[] args) {
Calendar calendar = new GregorianCalendar(2017, Calendar.JANUARY , 25);
calendar.set(Calendar.HOUR, 10);
calendar.set(Calendar.MINUTE, 42);
calendar.set(Calendar.SECOND, 12);
calendar.roll(Calendar.MONTH, -2);
System.out.println(calendar.getTime());
} Ми зробабо те саме, що й у попередньому прикладі — відібрали 2 місяці від поточної дати. Але тепер код спрацював по-іншому: місяць змінився з січня на листопад, але рік як був 2017-м, так і залишився! Висновок:
Sat Nov 25 10:42:12 MSK 2017 Далі. Як ми й казали вище, всі поля об'єкта Calendarможна отримати окремо. За це відповідає метод get():
public static void main(String[] args) {
GregorianCalendar calendar = new GregorianCalendar(2017, Calendar.JANUARY , 25);
calendar.set(Calendar.HOUR, 10);
calendar.set(Calendar.MINUTE, 42);
calendar.set(Calendar.SECOND, 12);
System.out.println("Рік:" + calendar.get(Calendar.YEAR));
System.out.println("Місяць:" + calendar.get(Calendar.MONTH));
System.out.println("Порядковий номер тижня на місяці:" + calendar.get(Calendar.WEEK_OF_MONTH));//порядковий номер тижня на місяці
System.out.println("Кількість: " + calendar.get(Calendar.DAY_OF_MONTH));
System.out.println("Годинник:" + calendar.get(Calendar.HOUR));
System.out.println("Хвабони:" + calendar.get(Calendar.MINUTE));
System.out.println("Секунди:" + calendar.get(Calendar.SECOND));
System.out.println(Мілісекунди: + calendar.get(Calendar.MILLISECOND));
} Висновок:
Год: 2017
Месяц: 0
Порядковый номер недели в месяце: 4
Число: 25
Часы: 10
Минуты: 42
Секунды: 12
Миллисекунды: 0 Тобто крім "супер-сеттера" в класі Calendarє ще й "супер-геттер" Ще один цікавий момент - це, звичайно, робота з ерами. Для створення дати "до нашої ери" потрібно використовувати поле Calendar.Era Наприклад, створимо дату, що позначає битву при Каннах, в якій Ганнібал переміг військо Риму. Це сталося 2 серпня 216 р. до зв. е.:
public static void main(String[] args) {
GregorianCalendar cannes = new GregorianCalendar(216, Calendar.AUGUST, 2);
cannes.set(Calendar.ERA, GregorianCalendar.BC);
DateFormat df = new SimpleDateFormat("dd MMM yyy GG");
System.out.println(df.format(cannes.getTime()));
} Тут ми використовували клас SimpleDateFormat, щоб вивести дату у більш зрозумілому нам форматі (літери “GG” відповідають саме за виведення ери). Висновок:
02 авг 216 до н.э. У класі Calendarє ще багато методів та констант, почитай про них у документації:
Переклад рядка у Date
Для перекладу String в Date можна скористатися допоміжним класом Java - SimpleDateFormat . Це клас, який потрібен для приведення дати в визначальний формат.
У свою чергу, він дуже схожий на DateFormat . Єдина помітна різниця між ними полягає в тому, що SimpleDateFormat можна використовувати для форматування (перетворення дати в рядок) та для парсингу рядка в дату з підтримкою мовного стандарту, тоді як DateFormat не підтримує мовний стандарт. Крім того, DateFormat – це абстрактний клас, який забезпечує базову підтримку для форматування та аналізу дат, а SimpleDateFormat – це конкретний клас, який розширює клас DateFormat. Ось так виглядає приклад створення об'єкта SimpleDateFormat та форматування Date:
SimpleDateFormat formater = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Date date = new Date(1212121212121L);
System.out.println(formatter.format(date)); У наведеному вище прикладі ми використовували шаблон "yyyy-MM-dd HH:mm:ss", який означає:
- 4 цифри на рік (yyyy);
- 2 цифри на місяць (ММ);
- 2 цифри на день (dd);
- 2 цифри для годинника у 24-годинному форматі (HH);
- 2 цифри на хвабони (mm);
- 2 цифри за секунди (ss).
2008-05-30 08:20:12 Шаблонних букв для класу SimpleDateFormat досить багато. Щоб ти не заплутався, ми зібрали їх у таблицю:
| Символ | Опис | приклад |
|---|---|---|
| G | ера (в англійській локалізації - AD і BC) | н.е. |
| y | рік (4-х значне число) | 2020 |
| yy | рік (останні 2 цифри) | 20 |
| yyyy | рік (4-х значне число) | 2020 |
| M | номер місяця (без лідируючих нулів) | 8 |
| MM | номер місяця (з лідируючими нулями, якщо порядковий номер місяця < 10) | 04 |
| MMM | трилітерне скорочення місяця (відповідно до локалізації) | січ |
| MMMM | повна назва місяця | Червень |
| w | тиждень у році (без лідируючих нулів) | 4 |
| ww | тиждень у році (з лідируючими нулями) | 04 |
| W | тиждень у місяці (без лідируючих нулів) | 3 |
| WW | тиждень у місяці (з лідируючим нулем) | 03 |
| D | день у році | 67 |
| d | день місяця (без лідируючих нулів) | 9 |
| dd | день місяця (з лідируючими нулями) | 09 |
| F | день тижня на місяці (без лідируючих нулів) | 9 |
| FF | день тижня на місяці (з лідируючими нулями) | 09 |
| E | день тижня (скорочення) | Вт |
| EEEE | день тижня (повністю) | п'ятниця |
| u | номер дня тижня (без лідируючих нулів) | 5 |
| uu | номер дня тижня (з лідируючими нулями) | 05 |
| a | маркер AM/PM | AM |
| H | годинник у 24-годинному форматі без лідируючих нулів | 6 |
| HH | годинник у 24-годинному форматі з лідируючим нулем | 06 |
| k | кількість годин у 24-годинному форматі | 18 |
| K | кількість годин у 12-годинному форматі | 6 |
| h | час у 12-годинному форматі без лідируючих нулів | 6 |
| hh | час у 12-годинному форматі з лідируючим нулем | 06 |
| m | хвабони без лідируючих нулів | 32 |
| mm | хвабони з лідируючим нулем | 32 |
| s | секунди без лідируючих нулів | 11 |
| ss | секунди з лідируючим нулем | 11 |
| S | мілісекунди | 297 |
| z | часовий пояс | EET |
| Z | часовий пояс у форматі RFC 822 | 300 |
| Шаблон | приклад |
|---|---|
| dd-MM-yyyy | 01-11-2020 |
| yyyy-MM-dd | 2019-10-01 |
| HH:mm:ss.SSS | 23:59.59.999 |
| yyyy-MM-dd HH:mm:ss | 2018-11-30 03:09:02 |
| yyyy-MM-dd HH:mm:ss.SSS | 2016-03-01 01:20:47.999 |
| yyyy-MM-dd HH:mm:ss.SSS Z | 2013-13-13 23:59:59.999 +0100 |
-
Створюємо рядок, з якого потрібно задати дату:
String strDate = "Sat, April 4, 2020"; -
Створюємо новий об'єкт SimpleDateFormat із шаблоном, який збігається з тим, що у нас у рядку (інакше розпарсувати не вийде):
SimpleDateFormat formatter = new SimpleDateFormat("EEE, MMMM d, yyyy", Locale.ENGLISH);Як ви бачите, у нас тут виник аргумент Locale. Якщо ми його опустимо, він буде використовувати значення Locale за умовчанням, яке завжди є англійською.
Якщо мовний стандарт не збігається з вхідним рядком, то рядкові дані, прив'язані до мови, як у нас Mon або April , не будуть розпізнані та викликатимуть падіння - java.text.ParseException, навіть якщо шаблон підходить.
Проте, можна не вказувати формат, якщо ми використовуємо шаблон, який не прив'язаний до мови. Як приклад - yyyy-MM-dd HH:mm:ss
-
Створюємо дату за допомогою формату, який у свою чергу парсить її з вхідного рядка:
try { Date date = formatter.parse(strDate); System.out.println(date); } catch (ParseException e) { e.printStackTrace(); }Виведення в консоль:
Sat Apr 04 00:00:00 EEST 2020Хммм….Але формат уже не той!
Щоб зробити той самий формат, знову використовуємо форматтер:
System.out.println(formatter.format(date));Виведення в консоль:
Sat, April 4, 2020
SimpleDateFormat та Calendar
SimpleDateFormat дозволить тобі форматувати всі створювані об'єкти Date та Calendar для подальшого використання. Розглянемо такий цікавий момент, як робота з ерами. Для створення дати "до нашої ери" потрібно використовувати поле Calendar.Era Наприклад, створимо дату, що означає битву при Каннах, в якій Ганнібал переміг військо Риму. Це сталося 2 серпня 216 р. до зв. е.:public static void main(String[] args) {
GregorianCalendar cannes = new GregorianCalendar(216, Calendar.AUGUST, 2);
cannes.set(Calendar.ERA, GregorianCalendar.BC);
DateFormat df = new SimpleDateFormat("dd MMM yyy GG");
System.out.println(df.format(cannes.getTime()));
} Тут ми використовували клас SimpleDateFormat, щоб вивести дату у більш зрозумілому нам форматі (як зазначено вище, літери “GG” відповідають саме за виведення ери). Висновок:
02 авг 216 до н.э.
Java Date Format
А ось ще один випадок. Припустимо, що цей формат дати нас не влаштовує:
Sat Nov 25 10:42:12 MSK 2017 Так ось. За допомогою наших можливостей у java date format його можна поміняти його на свій власний, без особливих складнощів:
public static void main(String[] args) {
SimpleDateFormat dateFormat = new SimpleDateFormat("EEEE, d MMMM yyyy");
Calendar calendar = new GregorianCalendar(2017, Calendar.JANUARY , 25);
calendar.set(Calendar.HOUR, 10);
calendar.set(Calendar.MINUTE, 42);
calendar.set(Calendar.SECOND, 12);
calendar.roll(Calendar.MONTH, -2);
System.out.println(dateFormat.format(calendar.getTime()));
} Висновок:
суббота, 25 Ноябрь 2017 Набагато краще, так? :)
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ