Java Data i czas

⚡ Inteligentne podsumowanie

Java Obsługa daty i godziny łączy starsze klasy java.util.Date i SimpleDateFormat z nowoczesnym interfejsem API java.time wprowadzonym w Java 8, zapewniając deweloperom niezmienne, bezpieczne wątkowo typy do dokładnej pracy z kalendarzem.

  • 🕒 Data dziedziczenia: Klasa java.util.Date przechowuje momenty w milisekundach i drukuje domyślny ciąg znaków za pomocą metody toString.
  • 🔤 Litery wzorcowe: SimpleDateFormat używa liter, takich jak rrrr, MM, dd, GG, mm, ss i zzz, aby definiować niestandardowe formaty wyjściowe.
  • ⚖️. Porównanie: Metoda compareTo zwraca liczbę całkowitą ujemną, zerową lub dodatnią, aby uporządkować chronologicznie dwie instancje Date.
  • 🆕 Nowoczesne API: LocalDate, LocalDateTime, ZonedDateTime i Instant w java.time zastępują obiekty Date i Calendar obiektami niezmiennymi.
  • 🧵 Bezpieczeństwo wątków: DateTimeFormatter jest niezmienny i można go bezpiecznie udostępniać, natomiast SimpleDateFormat wymaga synchronizacji lub wrappera ThreadLocal.
  • 🔁 Interoperacyjność: Konwertuj między starym i nowym interfejsem API za pomocą pomocniczych funkcji Date.toInstant, Date.from i Calendar.toInstant.

Java Data i czas

Obsługa dat i godzin w Java to rutynowy element tworzenia logiki harmonogramowania, rejestrowania znaczników czasu, raportów i ścieżek audytu. Przed napisaniem jakiegokolwiek kodu warto poznać parametry składające się na datę:

  • rok (dwu- lub czterocyfrowy).
  • miesiąc (jako dwie cyfry, jako pierwsze trzy litery miesiąca lub jako pełna nazwa miesiąca).
  • dane (faktyczny numer dnia miesiąca).
  • dzień (nazwa dnia w danej dacie, np. niedz., pon., wt.).

Java Ujawnia wiele innych parametrów opisujących moment na osi czasu, w tym erę, tydzień w roku, strefę czasową i przesunięcie. Poniższe sekcje omawiają każdy z nich wraz z przykładami do uruchomienia.

Jak korzystać z daty w Java

Wyświetl datę w Java

Java zapewnia Date klasa w java.util Pakiet. Klasa przechowuje konkretny moment z dokładnością do milisekundy i oferuje metody pomocnicze do drukowania, porównywania i formatowania tego momentu. Aby uzyskać aktualną datę i godzinę, utwórz instancję klasy za pomocą jej domyślnego konstruktora:

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());
    }
}

Wyjście:

Wed Nov 29 06:36:22 UTC 2017

Przykład drukuje datę w domyślnym formacie toString. Aby wyświetlić ten sam moment w innym wzorcu, najpierw musisz zrozumieć litery formatujące, które… Java używa.

SimpleDateFormat: analizuj i formatuj daty

SimpleDateFormat klasa w java.text konwertuje Date obiekt do sformatowanego ciągu i analizuje sformatowany ciąg z powrotem do DateUżywa liter wzorcowych, które odpowiadają składowej daty lub godziny. Poniższa tabela zawiera listę wszystkich obsługiwanych liter:

ListSkładnik daty lub godzinyPrzykład
GOznaczenie epokiAD
yRok2026
MMiesiąc w rokuLipiec lub lipiec lub 07
wTydzień w roku27
WTydzień w miesiącu2
DDzień w roku189
dDzień w miesiącu10
FDzień tygodnia w miesiącu2
ENazwa dnia w tygodniuwtorek lub wtorek
uNumer dnia tygodnia (1 = Monday, 7 = niedziela)1
aZnak AM lub PMPM
HGodzina w dniu (0-23)0
kGodzina w dniu (1-24)24
KGodzina w AM lub PM (0-11)0
hGodzina w AM lub PM (1-12)12
mMinuta w godzinie30
sDrugi w ciągu minuty55
SMilisekunda978
zStrefa czasowa (nazwa)Czas pacyficzny; PST; GMT-08:00
ZStrefa czasowa (przesunięcie RFC 822)-0800
XStrefa czasowa (przesunięcie ISO 8601)-08 lub -0800 lub -08:00

Nie musisz pamiętać całej tabeli. Sięgaj do niej za każdym razem, gdy tworzysz nowy wzór.

Jak korzystać z SimpleDateFormat

SimpleDateFormat jest podklasą DateFormat Umożliwia formatowanie i analizowanie dat za pomocą liter wzorca powyżej. Połącz litery, aby opisać dokładnie ciąg znaków, który chcesz wygenerować lub odczytać.

Na przykład:

  1. Wymagany format daty: 2012.10.23, 20:20:45 czasu PST. Odpowiedni wzór formatu to yyyy.MM.dd HH:mm:ss zzz.
  2. Wymagany format daty: 09:30:00 AM 23-May-2012. Odpowiedni wzór formatu to hh:mm:ss a dd-MMM-yyyy.

Wskazówka: Uważaj na wielkość liter. Wielkie litery M miesiąc, mała litera m jest minuta. Wielka litera H jest zegarem 24-godzinnym, małymi literami h to zegar 12-godzinny. Pomieszanie ich daje po cichu błędne wyniki.

Poniższy program drukuje bieżącą datę dwukrotnie – raz w formacie domyślnym i raz za pomocą wzorca 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));
    }
}

Wyjście:

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

Przykład porównania dat

Przykład porównania dat

Najbardziej niezawodny sposób na zamówienie dwóch Date obiekty to jest compareTo() Metoda. Zwraca ujemną liczbę całkowitą, gdy obiekt wywołujący jest wcześniejszy, zero, gdy obie instancje są równe, oraz dodatnią liczbę całkowitą, gdy obiekt wywołujący jest późniejszy. Poniższy fragment kodu analizuje dwa ciągi dat i wyświetla ich względną kolejność:

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");
        }
    }
}

Wyjście:

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

Uwaga: Oryginalny kod używał wzorca dd-mm-yyyy. Małe litery mm Litera oznacza minutę, a nie miesiąc, więc parser po cichu wygenerował błędną wartość miesiąca. Powyższa poprawka używa wielkich liter. MM dla miesiąca, co jest poprawnym wzorem literowym.

Java 8 Nowoczesne API daty i czasu (java.time)

Java 8 wprowadził java.time package, przeprojektowane API inspirowane biblioteką Joda-Time. Nowe klasy są niezmienne, bezpieczne dla wątków i oddzielają kalendarz ludzki od osi czasu maszyny. Najpopularniejsze typy to:

  • LocalDate na datę bez określonej godziny ani strefy czasowej (na przykład urodziny).
  • LocalTime dla czasu na zegarze ściennym bez daty i strefy czasowej.
  • LocalDateTime dla daty i godziny bez strefy czasowej.
  • ZonedDateTime dla daty i godziny w określonej strefie czasowej.
  • OffsetDateTime dla daty i godziny z przesunięciem UTC, ale bez nazwanej strefy.
  • Instant dla znacznika czasu maszyny mierzonego od epoki UNIX.
  • Duration oraz Period dla kwot opartych na czasie i dacie.

Poniższy przykład drukuje bieżącą datę, godzinę, znacznik czasu i strefę czasową za pomocą nowoczesnego interfejsu 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);
    }
}

Każdy typ ma metody fabryczne (now, of, parse) i operacje niezmienne (plusDays, minusHours, withYear) zwracające nową wartość zamiast mutować oryginalny obiekt.

DateTimeFormatter: Formatowanie dat w nowoczesnym formacie Java

DateTimeFormatter in java.time.format Zastępuje SimpleDateFormat. Używa tego samego stylu liter wzorcowych, jest niezmienna i można ją bezpiecznie udostępniać między wątkami bez dodatkowej synchronizacji. Klasa udostępnia również gotowe stałe, takie jak ISO_LOCAL_DATE oraz ISO_ZONED_DATE_TIME dla formatów standardowych.

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);
    }
}

Aby porównać dwie daty w nowoczesnym API, wywołaj isBefore, isAfterlub isEqual. Te metody są bardziej przejrzyste niż compareTo i pracować z każdym java.time class.

Bezpieczeństwo wątków i najlepsze praktyki Java Data i czas

Obie java.util.Date oraz SimpleDateFormat poprzedzają współczesną współczesność Java, a każda z nich ma swoje pułapki. Postępuj zgodnie z poniższymi praktykami, aby zapewnić poprawną obsługę dat w kodzie produkcyjnym:

  • Preferuj java.time zamiast Date i Calendar. Nowe typy są niezmienne i bezpieczne pod kątem wątków, a także dokładniej modelują domenę (daty bez czasu, czasy bez stref itd.).
  • Nie udostępniaj SimpleDateFormat pomiędzy wątkami. Klasa przechowuje wewnętrzny stan analizy i nie jest bezpieczna dla wątków. Zawiń ją w ThreadLocal, zsynchronizuj na instancji lub przełącz się na DateTimeFormatter.
  • Zawsze określaj ustawienia regionalne. Nazwy miesięcy i dni zmieniają się wraz z domyślną lokalizacją JVM, co powoduje, że wzorce takie jak MMM oraz EEE nieprzenośny. Przekaż ustawienia regionalne jawnie (na przykład, Locale.ENGLISH).
  • Podaj dokładne informacje o strefach czasowych. LocalDateTime nie ma strefy, więc przekształć na ZonedDateTime or Instant zawsze, gdy liczy się konkretny moment, zwłaszcza w przypadku dzienników, kolumn bazy danych i obciążeń sieciowych.
  • Należy zachować ostrożność podczas konwersji pomiędzy obydwoma interfejsami API. Zastosowanie date.toInstant(), Date.from(instant), calendar.toInstant().atZone(zone) na granicy między kodem starym i nowoczesnym.
  • Przechowuj znaczniki czasu w formacie UTC. Wytrwaj i transmit daty w formacie UTC ( Instant lub ciąg ISO 8601) i konwertować do strefy użytkownika tylko podczas wyświetlania.

FAQ

Wywołaj LocalDateTime.now() z pakietu java.time, aby uzyskać datę i godzinę w strefie systemowej, lub LocalDate.now() w przypadku samej daty. W starszych wersjach Java, użyj nowego java.util.Date(), aby uzyskać aktualną chwilę.

java.util.Date reprezentuje moment w milisekundach od epoki i jest zmienny. LocalDate modeluje datę kalendarzową bez czasu ani strefy czasowej, jest niezmienny i bezpieczny dla wątków oraz oferuje bardziej przejrzyste metody, takie jak plusDays i isBefore.

Nie. SimpleDateFormat zachowuje zmienny stan analizy i generuje błędne wyniki, gdy jest udostępniany między wątkami. Należy go umieścić w obiekcie ThreadLocal, zsynchronizować na instancji lub przełączyć na formater DateTimeFormatter, który jest niezmienny i bezpieczny.

Przekaż dokładny ciąg „rrrr-MM-dd”. Wielka litera MM oznacza miesiąc, mała litera mm oznacza minutę. Aby uzyskać pełną datę i godzinę, użyj „rrrr-MM-dd GG:mm:ss”. Zawsze określaj lokalizację, aby nazwy miesięcy były powtarzalne.

W przypadku starszej wersji Date należy użyć metody compareTo, która zwraca ujemną, zerową lub dodatnią wartość int. W przypadku java.time należy wywołać metodę isBefore, isAfter lub isEqual dla obiektu LocalDate lub Instant. Oba podejścia respektują kolejność chronologiczną.

Wywołaj date.toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime(). Aby wrócić, użyj Date.from(localDateTime.atZone(ZoneId.systemDefault()).toInstant()). Wybierz strefę jawnie, gdy tylko ma to znaczenie.

Modele sztucznej inteligencji trenowane na korpusach dzienników i dokumentów wnioskują o prawdopodobnym wzorcu z przykładowych ciągów znaków i zwracają pasujący wzorzec DateTimeFormatter. Klasyfikatory uczenia maszynowego sygnalizują również niejednoznaczne pola, takie jak kolejność miesiąc-dzień lub dzień-miesiąc.

Tak. GitHub Copilot sugeruje wzorce DateTimeFormatter, konwersje ZonedDateTime i JUnit testy pod kątem danych wyjściowych zależnych od ustawień regionalnych. RevPrzed zatwierdzeniem sprawdź każdą sugestię pod kątem prawidłowych liter wzorca, ustawień regionalnych i strefy czasowej.

Podsumuj ten post następująco: