Java Дата і час проведення

⚡ Розумний підсумок

Java Обробка дати та часу поєднує застарілі класи java.util.Date та SimpleDateFormat із сучасним API java.time, представленим у Java 8, що надає розробникам незмінні, потокобезпечні типи для точної роботи з календарем.

  • 🕒 Дата успадкування: Клас java.util.Date зберігає миттєве значення в мілісекундах та виводить рядок за замовчуванням через toString.
  • 🔤 Візерунок літер: SimpleDateFormat використовує такі літери, як рррр, ММ, дд, ГГ, мм, сс та zzz, для визначення користувацьких форматів виводу.
  • 🇧🇷 Порівняння: Метод compareTo повертає від’ємне, нульове або додатне ціле число, щоб упорядкувати два екземпляри Date у хронологічному порядку.
  • 🆕 Сучасний API: LocalDate, LocalDateTime, ZonedDateTime та Instant у java.time замінюють Date та Calendar незмінними об'єктами.
  • 🧵 Безпека потоків: DateTimeFormatter є незмінним та безпечним для спільного використання, тоді як SimpleDateFormat потребує синхронізації або обгортки ThreadLocal.
  • 🔁 Сумісність: Конвертуйте між старим та новим API за допомогою помічників Date.toInstant, Date.from та Calendar.toInstant.

Java Дата і час проведення

Обробка дат і часу в Java є рутинною частиною побудови логіки планування, позначок часу журналів, звітів та журналів аудиту. Перш ніж писати будь-який код, корисно знати параметри, з яких складається дата:

  • Команда рік (у двох або чотирьох цифрах).
  • Команда місяць (як дві цифри, як перші три літери місяця або як повна назва місяця).
  • Команда дата (фактичний номер дня місяця).
  • Команда день (назва дня на вказану дату, наприклад, Нд, Пн, Вт).

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

Як використовувати Date in Java

Показати дату в Java

Java забезпечує Date клас в java.util пакет. Клас зберігає певний момент часу з точністю до мілісекунд та пропонує допоміжні методи для друку, порівняння та форматування цього моменту. Щоб отримати поточну дату та час, створіть екземпляр класу за допомогою його конструктора за замовчуванням:

import java.util.Date;

class Date_Ex1 {
    public static void main(String args[]) {
        // Instantiate a Date object by invoking its constructor
        Date objDate = new Date();
        // Display the Date and Time using toString()
        System.out.println(objDate.toString());
    }
}

вихід:

Wed Nov 29 06:36:22 UTC 2017

У цьому прикладі дата виводиться у форматі toString за замовчуванням. Щоб відобразити той самий момент у іншому шаблоні, спочатку потрібно зрозуміти літери форматування, які Java використовує.

SimpleDateFormat: аналіз і форматування дат

Команда SimpleDateFormat клас в java.text перетворює Date об'єкт у форматований рядок та аналізує форматований рядок назад у DateВін використовує шаблонні літери, що відповідають компоненту дати або часу. У таблиці нижче перелічені всі підтримувані літери:

листКомпонент дати або часуПриклад
GПозначник ериAD
yрік2026
MМісяць у роціЛипень або липень або 07
wТиждень у році27
WТиждень у місяці2
DДень у році189
dДень у місяці10
FДень тижня в місяці2
EНазва дня в тижнівівторок або вт
uНомер дня тижня (1 = Monday, 7 = неділя)1
aМаркер AM або PMPM
HГодина в день (0-23)0
kГодина в день (1-24)24
KГодина в AM або PM (0-11)0
hГодина в AM або PM (1-12)12
mХвилина за годиною30
sСекунда за хвилину55
SМільсекунда978
zЧасовий пояс (назва)стандартний тихоокеанський час; PST; GMT-08:00
ZЧасовий пояс (зсув RFC 822)-0800
XЧасовий пояс (зміщення ISO 8601)-08 або -0800 або -08:00

Вам не потрібно запам'ятовувати всю таблицю. Звертайтеся до неї щоразу, коли створюєте новий візерунок.

Як використовувати SimpleDateFormat

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

Наприклад:

  1. Потрібний формат дати: 2012.10.23 20:20:45 PSTВідповідний шаблон форматування — yyyy.MM.dd HH:mm:ss zzz.
  2. Потрібний формат дати: 09:30:00 AM 23-May-2012Відповідний шаблон форматування — hh:mm:ss a dd-MMM-yyyy.

Порада: Слідкуйте за регістром літер. Великі літери M місяць, мал. літера m хвилина. Великі літери H це 24-годинний годинник, малими літерами h це 12-годинний формат часу. Їх переплітання призводить до непомітно неправильного виводу.

Наведена нижче програма друкує поточну дату двічі: один раз у форматі за замовчуванням, а інший раз за допомогою шаблону SimpleDateFormat:

import java.text.SimpleDateFormat;
import java.util.Date;

class TestDates_Format {
    public static void main(String args[]) {
        // Current system date and time is assigned to objDate
        Date objDate = new Date();
        System.out.println(objDate);

        // Build the target pattern and format the date
        String strDateFormat = "hh:mm:ss a dd-MMM-yyyy";
        SimpleDateFormat objSDF = new SimpleDateFormat(strDateFormat);
        System.out.println(objSDF.format(objDate));
    }
}

вихід:

Wed Nov 29 06:31:41 UTC 2017
06:31:41 AM 29-Nov-2017

Приклад порівняння дат

Приклад порівняння дат

Найнадійніший спосіб замовити два Date об'єкти є compareTo() метод. Він повертає від'ємне ціле число, коли викликаючий об'єкт відбувається раніше, нуль, коли обидва моменти часу рівні, та додатне ціле число, коли викликаючий об'єкт відбувається пізніше. Фрагмент коду нижче аналізує два рядки дати та друкує їх відносний порядок:

import java.text.SimpleDateFormat;
import java.text.ParseException;
import java.util.Date;

class TestDates_Compare {
    public static void main(String args[]) throws ParseException {

        SimpleDateFormat objSDF = new SimpleDateFormat("dd-MM-yyyy");
        Date dt_1 = objSDF.parse("20-08-1981");
        Date dt_2 = objSDF.parse("12-10-2012");

        System.out.println("Date1 : " + objSDF.format(dt_1));
        System.out.println("Date2 : " + objSDF.format(dt_2));

        // compareTo returns > 0 when dt_1 is after dt_2
        if (dt_1.compareTo(dt_2) > 0) {
            System.out.println("Date 1 occurs after Date 2");
        }
        // compareTo returns < 0 when dt_1 is before dt_2
        else if (dt_1.compareTo(dt_2) < 0) {
            System.out.println("Date 1 occurs before Date 2");
        }
        // compareTo returns 0 when both dates are equal
        else {
            System.out.println("Both are the same date");
        }
    }
}

вихід:

Date1 : 20-08-1981
Date2 : 12-10-2012
Date 1 occurs before Date 2

Примітка: У вихідному коді використовувався шаблон dd-mm-yyyy. Нижній регістр mm літера — це хвилина, а не місяць, тому парсер непомітно видає неправильне значення місяця. У наведеному вище виправленні використовуються великі літери. MM для місяця, що є правильною літерою шаблону.

Java 8 Сучасний API дати та часу (java.time)

Java 8 представив java.time пакет, перероблений API, натхненний бібліотекою Joda-Time. Нові класи є незмінними, потокобезпечними та відокремлюють людський календар від машинної часової шкали. Найпоширенішими типами є:

  • LocalDate для дати без зазначення часу чи поясу (наприклад, день народження).
  • LocalTime для настінного годинника без дати чи часового поясу.
  • LocalDateTime для дати й часу без поясу.
  • ZonedDateTime для дати та часу з певним часовим поясом.
  • OffsetDateTime для дати й часу зі зміщенням UTC, але без іменованої зони.
  • Instant для машинної позначки часу, виміряної з епохи UNIX.
  • Duration та Period для сум, що базуються на часі та даті.

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

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.ZonedDateTime;
import java.time.Instant;
import java.time.ZoneId;

class ModernDateDemo {
    public static void main(String args[]) {
        LocalDate today = LocalDate.now();
        LocalDateTime now = LocalDateTime.now();
        ZonedDateTime zoned = ZonedDateTime.now(ZoneId.of("Asia/Kolkata"));
        Instant epoch = Instant.now();

        System.out.println("LocalDate     : " + today);
        System.out.println("LocalDateTime : " + now);
        System.out.println("ZonedDateTime : " + zoned);
        System.out.println("Instant       : " + epoch);
    }
}

Кожен тип має фабричні методи (now, of, parse) та незмінні операції (plusDays, minusHours, withYear), які повертають нове значення замість того, щоб змінювати оригінальний об'єкт.

DateTimeFormatter: Форматування дат у сучасному форматі Java

DateTimeFormatter in java.time.format замінює SimpleDateFormatВін використовує той самий стиль шаблонних літер, є незмінним і безпечним для спільного використання в різних потоках без додаткової синхронізації. Клас також надає готові константи, такі як ISO_LOCAL_DATE та ISO_ZONED_DATE_TIME для стандартних форматів.

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;

class FormatterDemo {
    public static void main(String args[]) {
        LocalDateTime now = LocalDateTime.now();

        DateTimeFormatter iso = DateTimeFormatter.ISO_LOCAL_DATE_TIME;
        DateTimeFormatter human = DateTimeFormatter.ofPattern("hh:mm:ss a dd-MMM-yyyy");

        System.out.println(now.format(iso));
        System.out.println(now.format(human));

        LocalDateTime parsed = LocalDateTime.parse("2026-07-04T09:30:00", iso);
        System.out.println("Parsed back : " + parsed);
    }
}

Щоб порівняти дві дати в сучасному API, викличте isBefore, isAfterабо isEqualЦі методи читаються чіткіше, ніж compareTo і працювати з кожним java.time клас.

Безпека потоків та найкращі практики для Java Дата і час проведення

обидві java.util.Date та SimpleDateFormat передували сучасному одночасному Java, і кожен має відомі недоліки. Дотримуйтесь наведених нижче практик, щоб забезпечити правильну обробку дат у продакшн-коді:

  • Надайте перевагу java.time над Date та Calendar. Нові типи є незмінними та потокобезпечними, і вони моделюють домен точніше (дати без часу, час без поясів тощо).
  • Не поширюйте SimpleDateFormat між потоками. Клас зберігає внутрішній стан розбору та не є потокобезпечним. Оберніть його в ThreadLocal, синхронізувати в екземплярі або переключитися на DateTimeFormatter.
  • Завжди вказуйте локалізацію. Назви місяців і днів змінюються відповідно до локалізації JVM за замовчуванням, що створює такі шаблони, як MMM та EEE непортативний. Явно передайте локалізацію (наприклад Locale.ENGLISH).
  • Чітко вказуйте часові пояси. LocalDateTime не має зони, тому конвертуйте в ZonedDateTime or Instant щоразу, коли важливий точний момент, особливо для журналів, стовпців бази даних та мережевих корисних навантажень.
  • Ретельно конвертуйте між двома API. Скористайтеся кнопкою date.toInstant(), Date.from(instant) та calendar.toInstant().atZone(zone) на межі між застарілим кодом та сучасним кодом.
  • Зберігати позначки часу в UTC. Наполягати та transmit дати за UTC (UTC Instant або рядок ISO 8601) та конвертувати в зону користувача лише під час відображення.

Поширені запитання

Викличте LocalDateTime.now() з пакета java.time для отримання дати та часу в системній зоні або LocalDate.now() лише для отримання дати. У старіших версіях Java, використовуйте new java.util.Date() для отримання поточного моменту.

java.util.Date представляє момент у мілісекундах з епохи та є змінним. LocalDate моделює календарну дату без часу чи поясу, є незмінним та потокобезпечним, а також пропонує зрозуміліші методи, такі як plusDays та isBefore.

Ні. SimpleDateFormat зберігає змінний стан розбору та видає неправильні результати, коли він спільно використовується між потоками. Оберніть його в ThreadLocal, синхронізуйте в екземплярі або перемкніться на DateTimeFormatter, який є незмінним та безпечним.

Передайте точний рядок «рррр-ММ-дд». Великі літери MM – це місяць, малі літери mm – хвилини. Для повної дати та часу використовуйте «рррр-ММ-дд ГГ:хх:сс». Завжди вказуйте локаль, щоб назви місяців можна було відтворювати.

Зі старою функцією Date використовуйте compareTo, яка повертає від'ємне, нульове або додатне ціле число. З java.time викличте isBefore, isAfter або isEqual для LocalDate або Instant. Обидва підходи враховують хронологічний порядок.

Викличте date.toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime(). Щоб повернутися назад, використовуйте Date.from(localDateTime.atZone(ZoneId.systemDefault()).toInstant()). Виберіть зону явно щоразу, коли важливий точний момент.

Моделі штучного інтелекту, навчені на корпусах журналів та документів, виводять ймовірний шаблон зі зразків рядків та повертають відповідний шаблон DateTimeFormatter. Класифікатори машинного навчання також позначають неоднозначні поля, такі як порядок «місяць-день» проти «день-місяць».

Так. GitHub Copilot пропонує шаблони DateTimeFormatter, перетворення ZonedDateTime та JUnit тести на вивід, залежний від локалі. RevПерегляньте кожну пропозицію щодо правильних літер шаблону, локалізації та часового поясу, перш ніж фіксувати значення.

Підсумуйте цей пост за допомогою: