Kurs Java

Data i czas w Javie 8

W każdym systemie informatycznym funkcjonują mechanizmy obsługujące datę i czas. Zwykle bardzo ważne jest zapisywanie informacji o momencie wystąpienia czynności, zdarzenia lub innego elementu rzeczywistości opisywanej przez system. W Javie, przed erą Javy 8 istniał dosyć skromny zestaw rozwiązań do zarządzania takimi danymi.

Data przed Javą 8

W skrócie wyglądało to tak, że istniała klasa o nazwie Date, która wyznaczała datę i czas oraz klasa Calendar, której rolą było dostarczenie metod do manipulacji datą i czasem. Tak więc, jeśli chcieliśmy uzyskać bieżącą datę, po prostu tworzyliśmy obiekt klasy Date. Dodatkowo mogliśmy użyć formatera (klasa SimpleDateFormat), tak aby przedstawić takie dane w odpowiadającym nam formacie:
import java.text.SimpleDateFormat;
import java.util.Date;

public class Start {

    public static void main(String[] args) {

        Date dateBeforeJava8 = new Date();
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("YYYY-mm-dd HH:mm:ss");
        System.out.println(simpleDateFormat.format(dateBeforeJava8));
    }
}
Wynik wykonania kodu:
Java 8 - Data i czas przed Javą 8
Pobranie bieżącej daty i czasu można było wykonać również za pomocą klasy Calendar, ale klasa ta była używana głównie do modyfikacji daty/czasu. Mogliśmy dowolnie ustawiać dni, miesiące, lata, godziny itp. Kilka możliwości obrazuje poniższy przykład:
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;

public class Start {

    public static void main(String[] args) {

        Calendar calendar = Calendar.getInstance();
        Date dateBeforeJava8 = calendar.getTime(); // pobranie daty z obiektu kalendarza
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("YYYY-MM-dd HH:mm:ss");
        System.out.println(simpleDateFormat.format(dateBeforeJava8));

        calendar.set(Calendar.MONTH, 6); // ustawienie miesiąca *
        calendar.set(Calendar.DAY_OF_MONTH, 10); // ustawienie dnia w miesiącu
        System.out.println(simpleDateFormat.format(calendar.getTime()));

        calendar.add(Calendar.YEAR, 3); // dodanie lat do daty ustawionej daty w kalendarzu
        calendar.add(Calendar.DAY_OF_MONTH, 10); // dodanie dni do daty ustawionej daty w kalendarzu
        System.out.println(simpleDateFormat.format(calendar.getTime()));
    }
}
Wynik wykonania kodu:
Java 8 - Klasa Calendar
* Na uwagę zasługuje fakt, że numeracja miesięcy zaczyna się od zera, więc cyfra 6 oznacza lipiec.
Appa Notka. Uparcie piszemy o datach sprzed Javy 8 w czasie przeszłym, co może nieco zaskakiwać, skoro wspomniane tutaj klasy nadal są dostępne w Javie. Wynika to z tego, że praktycznie w każdym nowym systemie używany jest już zestaw klas i interfejsów z Javy 8. Pakiet rozwiązań dotyczący daty i czasu został w tej wersji znacząco rozszerzony, a także wyeliminowano wiele dotychczas występujących problemów.

Problemy z datami przed Javą 8

Można zadawać sobie pytanie dlaczego w Javie 8 wprowadzono całkiem nowy pakiet klas i interfejsów do zarządzania datą i czasem. Odpowiedź sprowadza się do przedstawienia kilku kluczowych problemów poprzedniego modelu:
  • Ubogie i nienajlepiej zaprojektowane API, co udowodnimy w tym rozdziale, omawiając alternatywy z wersji Java 8.
  • Klasa Date jest mutable, czyli można ją łatwo modyfikować, co w przypadku dat może być niebezpieczne.
  • Klasa SimpleDateFormat nie jest synchronizowana, co generuje problemy w systemach wielowątkowych.
  • Mizernie zaimplementowane zarządzanie strefami czasowymi. Sama klasa Date nie pozwala na podanie strefy czasowej.

Data w Java 8 - Wstęp

No to zaczynamy. Najpierw podstawy, czyli zapoznanie się z listą tematów, które rozwijamy w dalszej części tego rozdziału.

Zarządzanie datą i czasem zostało umieszczone w nowym pakiecie o nazwie java.time. To tam znajdują się nowe klasy, interfejsy i inne byty odpowiedzialne za prawidłową obsługę dat.

W ramach nowości w Javie 8 pojawiają się zupełnie nowe pojęcia:
  • Instant, czyli punkt w czasie
  • LocalDate - data w lokalnej (systemowej) albo zdefiniowanej przez nas strefie czasowej (bez przechowywania jej w obiekcie)
  • LocalTime - czas w lokalnej (systemowej) albo zdefiniowanej przez nas strefie czasowej (bez przechowywania jej w obiekcie)
  • LocalDateTime - data i czas w lokalnej (systemowej) albo zdefiniowanej przez nas strefie czasowej (bez przechowywania jej w obiekcie)
  • ZonedDateTime - data i czas w lokalnej (systemowej) albo zdefiniowanej przez nas strefie czasowej (przechowywana w obiekcie)
  • Duration - określenie czasu trwania w zakresie od nanosekund do liczby dni
  • Period - określenie czasu trwania w zakresie od dni do lat
  • TemporalAdjusters - dostosowanie daty do potrzeb za pomocą predefiniowanych metod
  • Nowe formatery dat - nowe sposoby formatowania daty i czasu
Tyle tytułem wstępu. Teraz wyjaśnimy wszystko po kolei, bazując na konkretnych przykładach.

Data w Java 8 - Instant vs Date

Klasa Instant reprezentuje konkretny punkt na linii czasu, a jej precyzja sięga nanosekund. Instant jest immutable, więc podczas próby modyfikacji obiektu tego typu uzyskujemy referencję do nowego obiektu, a obiekt modyfikowany pozostaje bez zmian. To duży plus, ponieważ nie musimy się martwić, że spotkamy się z problemami takimi jak w przypadku użycia klasy Date. Podobnie będzie z LocalTime, LocalDate, LocalDateTime i ZonedDateTime. One też są immutable.

Zróbmy teraz małe porównanie wyjaśniające, co oznacza to pojęcie. Stwórzmy klasę DateAndInstantProvider i przeanalizujmy różnicę miedzy immutable Instant a mutable Date:
import java.time.Instant;
import java.util.Date;

public class DateAndInstantProvider {

    // Stworzenie obiektu klasy DateAndInstantProvider 
    // automatycznie zainicjuje obiekty date i instant
    private Date date = new Date(); 
    private Instant instant = Instant.now();

    public Date getDate() {
        return date;
    }

    public Instant getInstant() {
        return instant;
    }
}
W kodzie głównym programu (poniżej) tworzymy obiekt klasy DateAndInstantProvider, w którym automatycznie inicjowane są pola date i instant (powyżej). Dalej pobieramy obie wartości z obiektu, a dokładniej uzyskujemy referencje do tych obiektów. Teraz przechodzimy do kluczowej części programu. W niej drukujemy daty przed i po zmianach obiektów. Po zmianie pobieramy jeszcze raz referencje bezpośrednio z dateAndInstantProvider. Okazuje się, że data typ Date zmieniła się, podczas gdy data typu Instant pozostała taka sama. Dowodzi do, że Instant jest immutable, w przeciwieństwie do Date, która jest mutable.

Po modyfikacji obiektu typu Instant otrzymaliśmy nowy obiekt tego typu (nazwaliśmy go newInstant) i tam znajduje się nasza nowa data.
import java.time.Instant;
import java.util.Date;

public class Start {

    public static void main(String[] args) {

        DateAndInstantProvider dateAndInstantProvider = new DateAndInstantProvider(); // tworzymy obiekt
        Date date = dateAndInstantProvider.getDate();
        Instant instant = dateAndInstantProvider.getInstant();

        System.out.println("Date before: " + date);
        date.setTime(0L); // zmieniamy
        System.out.println("Date after: " + dateAndInstantProvider.getDate()); // data jest zmieniona!

        System.out.println("Instant before: " + instant);
        Instant newInstant = instant.plusSeconds(60); // zmieniamy 
        System.out.println("Instant after: " + dateAndInstantProvider.getInstant()); // data taka sama

        System.out.println("newInstant: " + newInstant); // zmieniona data w nowym obiekcie
    }
}
Wynik wykonania kodu:
Wynik wykonania kodu - Date vs Instant
Appa Notka. Użycie instanta spowoduje, że data będzie podana w strefie czasowej UTC (to oznacza "Z" na końcu wydruku daty), więc ta klasa nie powinna być używana do zapisywania momentu wystąpienia wydarzeń, czy też poznawania bieżącej godziny. Traktujemy ją czysto technicznie, stosując na przykład do odmierzania czasu trwania określonych operacji. Po prostu, dzięki klasie Instant poznajesz dwa punkty w czasie i możesz wyznaczać różnice między nimi. W tej materii dowiesz się więcej, gdy przejdziemy do omawiania klasy Duration, która wspiera klasę Instant w jej działaniach.

Data w Java 8 - Użycie Instant

Tak jak zaznaczyliśmy w poprzednim paragrafie, klasa Instant pozwala nam na określenie konkretnego momentu w czasie. Pytanie, jakie jeszcze możliwości dostarcza nam ta klasa? Czy możemy na przykład obiekt tej klasy stworzyć z obiektu klasy Date albo wczytać datę podając stringa?

Odpowiedzi na te pytania znajdują się w komentarzach poniższego przykładu:
import java.time.Instant;
import java.util.Date;

public class Start {

    public static void main(String[] args) {

        // Jeszcze raz - bieżąca data
        System.out.println("Instant.now:");
        System.out.println(Instant.now());

        // Minimalna data (ekstremalnie daleko w przeszłości, liczona w miliaradach lat)
        System.out.println("Instant.min:");
        System.out.println(Instant.MIN);

        // Maksymalna data (ekstremalnie daleko w przyszłości, liczona w miliaradach lat)
        System.out.println("Instant.MAX:");
        System.out.println(Instant.MAX);

        // Konwersja z Date do Instant
        Instant instantFromDate = Instant.ofEpochMilli(new Date().getTime());
        System.out.println("Instant from Date:");
        System.out.println(instantFromDate);

        // Tworzenie Instant ze String-a
        Instant instantFromString = Instant.parse("2020-03-12T15:22:17Z");
        System.out.println("Instant from String:");
        System.out.println(instantFromString);
    }
}
Wynik wykonania kodu:
Wynik wykonania kodu - Użycie Instant
Można do tego jeszcze dodać metody aktualizujące (plus, minus) sekundy, millisekundy i nanosekundy, ale tym zajmiemy się dopiero za chwilę. Po prostu, aby udać się w tym kierunku, potrzebujesz jeszcze trochę wiedzy z innych zagadnień.

Zwróć uwagę, że klasa Instant co prawda wyznacza punkt w czasie, ale nie służy do określania dokładnej daty i godziny, pasującej do tego, co widzisz w systemie operacyjnym. Będzie ona zgodna z Twoim czasem systemowym tylko, jeśli przebywasz w strefie UTC, ale wtedy i tak nie powinieneś(-naś) jej zapisywać w aplikacji webowej w celu obsługi logiki biznesowej. Uzależnienie poprawnego zapisu daty i czasu od jednej strefy czasowej jest złym podejściem. W dalszej części rozdziału poznasz klasę, która nadaje się do tego o wiele lepiej (dla niecierpliwych: LocalDateTime)

Po wyjaśnieniu tematu instantów ruszamy dalej, tym razem w kierunku obsługi daty zgodnej z Twoimi ustawieniami systemowymi (a więc i Twoją strefą czasową).

Data w Java 8 - LocalDate

Ten paragraf należałoby rozpocząć od stwierdzenia, że jeśli zależy Ci na obsłudze samych dat (bez czasu) z prostym definiowaniem stref czasowych to "jesteś w domu". Do tego właśnie służy klasa LocalDate. Nie zapamiętuje ona informacji o strefie czasowej, ale podaje ją w strefie czasowej systemu operacyjnego (na którym uruchamiamy kod), bądź strefie podanej w postaci parametru ZoneId.

Co to znaczy, że nie zapamiętuje? To oznacza tyle, że po stworzeniu daty w określonej strefie czasu, przy późniejszym jej użyciu nie wiadomo, w jakiej strefie ona powstała. Innymi słowy, jeżeli stworzysz obiekt klasy LocalDate w strefie na przykład UTC, to w kolejnej linii kodu nie wyciągniesz z tego obiektu informacji, w jakiej strefie została utworzona data.

Ważne jest, aby zapamiętać, że LocalDate przechowuje informację tylko o samej dacie, bez czasu.
import java.time.LocalDate;
import java.time.Month;
import java.time.ZoneId;

public class Start {

    public static void main(String[] args) {

        // Bieżąca data na podstawie zegara systemowego (domyślna strefa czasowa naszego systemu):
        LocalDate localDate = LocalDate.now();
        System.out.println("LocalDate - System zone: " + localDate);
        // Bieżąca data w strefie azjatyckiej - Tokio:
        LocalDate localDateAsiaTokio = LocalDate.now(ZoneId.of("Asia/Tokyo"));
        System.out.println("LocalDate - Asia/Tokyo zone: " + localDateAsiaTokio);

        // Data złożona z roku, miesiąca i dnia:
        LocalDate java8FirstRelease = LocalDate.of(2014, Month.MARCH, 18); 
        System.out.println(java8FirstRelease);

        // Data ze stringa:
        LocalDate java8FirstReleaseParsed = LocalDate.parse("2014-03-18");
        System.out.println(java8FirstReleaseParsed);

        // Porównanie dwóch dat - czy data java8FirstRelease jest przed bieżącą datą:
        System.out.println("Is java8FirstRelease before localDate:");
        System.out.println(java8FirstRelease.isBefore(localDate));

        // Pobranie numeru dnia miesiąca, dnia tygodnia or numeru dnia w roku:
        System.out.println("Day of month: " + localDate.getDayOfMonth());
        System.out.println("Day of week: " + localDate.getDayOfWeek());
        System.out.println("Day of year: " + localDate.getDayOfYear());
    }
}
Wynik wykonania kodu:
Wynik wykonania kodu - LocalDate

Data w Java 8 - LocalTime

Było o dacie, to teraz przyszła kolej na klasę reprezentującą czas, a więc LocalTime. Reguły dotyczące lokalizacji w strefie czasowej są dokładnie takie same jak w przypadku LocalDate. Nie będziemy ich powtarzać, ponieważ już je znasz. Zapamiętaj, że klasa LocalTime określa tylko i wyłącznie czas. Nie zawiera informacji o dacie.
import java.time.LocalTime;
import java.time.ZoneId;

public class Start {

    public static void main(String[] args) {

        // Bieżący czas na podstawie zegara systemowego (domyślna strefa czasowa naszego systemu):
        LocalTime localTime = LocalTime.now();
        System.out.println(localTime);
        // Bieżący czas w strefie azjatyckiej - Tokio:
        LocalTime localTimeAsiaTokio = LocalTime.now(ZoneId.of("Asia/Tokyo"));
        System.out.println("LocalTime - Asia/Tokyo zone: " + localTimeAsiaTokio);

        // Czas złożony z godziny, minut i sekund oraz nanosekund:
        LocalTime movieStartTime = LocalTime.of(20, 15, 30, 15);
        System.out.println(movieStartTime);

        // Czas ze stringa:
        LocalTime movieStartTimeParsed = LocalTime.parse("20:15");
        System.out.println(movieStartTimeParsed);

        // Porównanie dwóch czasów - czy czas movieStartTimeParsed jest przed czasem bieżącym:
        System.out.println("Is movieStartTimeParsed before localTime:");
        System.out.println(movieStartTimeParsed.isBefore(localTime));

        // Pobranie godziny, minuty, sekundy oraz nanosekundy
        System.out.println("Hour: " + localTime.getHour());
        System.out.println("Minute: " + localTime.getMinute());
        System.out.println("Second: " + localTime.getSecond());
        System.out.println("Nano: " + localTime.getNano());
    }
}
Wynik wykonania kodu:
Wynik wykonania kodu - LocalTime

Data w Java 8 - LocalDateTime

Wreszcie przyszedł czas na danie główne. Klasa LocalDateTime przechowuje informacje zarówno o dacie, jak i o czasie. Reguły poznane w przypadku LocalDate także tutaj znajdują swoje zastosowanie. W dalszym ciągu data i czas określone przez obiekt tej klasy są zgodne ze strefą czasową systemu, na którym uruchamiasz kod, bądź strefą, którą podasz w postaci parametru stosownej metody.

W przypadku protych aplikacji z nieskomplikowaną logiką dotyczącą zmian stref czasowych klasa LocalDateTime jest w zupełności wystarczająca. Natomiast jeśli się okaże, że potrzebujesz czegoś więcej, wtedy warto rozważyć użycie klasy ZonedDateTime.
import java.time.LocalDateTime;
import java.time.Month;
import java.time.ZoneId;

public class Start {

    public static void main(String[] args) {

        // Bieżąca data i czas na podstawie zegara systemowego (domyślna strefa czasowa naszego systemu):
        LocalDateTime localDateTime = LocalDateTime.now();
        System.out.println(localDateTime);
        // Bieżąca data i czas w strefie azjatyckiej - Tokio:
        LocalDateTime localDateTimeAsiaTokio = LocalDateTime.now(ZoneId.of("Asia/Tokyo"));
        System.out.println("LocalDateTime - Asia/Tokyo zone: " + localDateTimeAsiaTokio);        

        // Data i czas złożony z godziny, minut i sekund oraz nanosekund:
        LocalDateTime startDateTime = LocalDateTime.of(2020, Month.APRIL, 21, 20, 15, 30, 15);
        System.out.println(startDateTime);

        // Data i czas ze stringa:
        LocalDateTime startDateTimeParsed = LocalDateTime.parse("2020-04-21T20:15");
        System.out.println(startDateTimeParsed);

        // Porównanie dwóch dat z czasem - czy czas startDateTimeParsed jest przed czasem localDateTime:
        System.out.println("Is startDateTimeParsed before localDateTime:");
        System.out.println(startDateTimeParsed.isBefore(localDateTime));

        // Pobranie godziny, minuty, sekundy oraz nanosekundy
        System.out.println("Hour: " + startDateTime.getHour());
        System.out.println("Minute: " + startDateTime.getMinute());
        System.out.println("Second: " + startDateTime.getSecond());
        System.out.println("Nano: " + startDateTime.getNano());
    }
}
Wynik wykonania kodu:
Wynik wykonania kodu - LocalDateTime

Data w Java 8 - Strefy czasowe

Zanim przejdziemy do klasy ZonedDateTime, wyjaśnimy jeszcze, skąd bierzemy informacje o strefach czasowych w Javie. Wszystkie strefy pochodzą z bazy informacyjnej IANA, znajdującej się pod adresem https://www.iana.org/time-zones. W kodzie Javy listę stref wyciągamy za pomocą metody getAvailableZoneIds z klasy ZoneId. Możemy też stworzyć obiekt tej klasy, który będzie reprezentował konkretną strefę. Taka umiejętność przyda się już w kolejnym paragrafie.
import java.time.ZoneId;
import java.util.Set;

public class Start {

    public static void main(String[] args) {

        Set<String> allZones = ZoneId.getAvailableZoneIds();
        allZones.forEach(System.out::println);

        ZoneId europeWarsawZone = ZoneId.of("Europe/Warsaw");
        System.out.println("Zone name: " + europeWarsawZone.toString());
    }
}

Wynik wykonania kodu:
Wynik wykonania kodu - Strefy czasowe

Data w Java 8 - ZonedDateTime

Najbogatszą klasą obsługującą datę i czas w Javie 8 jest ZonedDateTime. Oferuje ona zbliżoną funkcjonalność co LocalDateTime z tą różnicą, że przechowuje jeszcze informację o strefie czasowej, w której dana data i czas zostały pobrane.

Klasa ZonedDateTime daje nam wiele możliwości tworzenia daty i czasu wraz ze strefami czasowymi. Uruchomienie metody now zwraca informację o dacie i czasie z systemu, ale tym razem zawiera doklejoną informację o przesunięciu czasu oraz nazwie strefy czasowej (obrazek "Wynik wykonania kodu" pod snippetem kodu).

Wykonanie kolejnej metody z podaniem strefy czasowej zwraca bieżącą godzinę w tamtej strefie, czyli naszą godzinę przesuniętą o ZoneOffset. Przesunięcie wynosi 9 godzin w stosunku do UTC, a więc 7 godzin w porównaniu do naszej strefy czasu (my obecnie w czasie letnim jesteśmy przesunięci o 2 godziny względem UTC). Dalej wykonujemy operację odwrotną, tyle że z wykorzystaniem metody withZoneSameInstant. Data i godzina wracają do pierwotnej postaci.

Zanim przejdziemy do kolejnej operacji na strefach, ustawmy jeszcze zupełnie nową datę, tym razem złożoną z poszczególnych parametrów, takich jak rok, dzień, miesiąc itd. W tym celu wykorzystamy metodę of.

Kolejną opcją jest stworzenie obiektu klasy ZonedDateTime w danej strefie (LocalDateTime.now()) i doklejenie innej strefy bez zmiany daty i czasu. Ponownie z użyciem metody of. W tak stworzonym obiekcie będziemy mieli naszą datę, ale offset i strefa będą wyglądać, jakby data pochodziła z innej strefy (w tym przypadku Asia/Tokyo).

W ten sposób możemy manipulować strefami czasowymi w dowolny sposób. Na jasnozielono zaznaczyliśmy bieżącą datę w strefie amerykańskiej, z doklejoną strefą azjatycką.
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.ZonedDateTime;

public class Start {

    public static void main(String[] args) {

        // Bieżąca data i czas na podstawie zegara systemowego (domyślna strefa czasowa naszego systemu):
        ZonedDateTime zonedDateTime = ZonedDateTime.now();
        System.out.println(zonedDateTime);
        
        // Bieżąca data i czas w strefie azjatyckiej - Tokio:
        ZonedDateTime zonedDateTimeAsiaTokio = ZonedDateTime.now(ZoneId.of("Asia/Tokyo"));
        System.out.println("ZonedDateTime - Asia/Tokyo zone: " + zonedDateTimeAsiaTokio);
        // Azjatycka data i czas w strefie europejskiej (data i godzina powinny być jak w zonedDateTime)
        ZonedDateTime zonedDateTimeEuropeBelgrade = zonedDateTimeAsiaTokio
                                                    .withZoneSameInstant(ZoneId.of("Europe/Belgrade"));
        System.out.println("ZonedDateTime - Europe/Belgrade zone: " + zonedDateTimeEuropeBelgrade);        

        // Data i czas złożony z godziny, minut i sekund oraz nanosekund:
        ZonedDateTime startDateTime  = ZonedDateTime.of(2020, 6, 21, 20, 15, 30, 15,
                                                        ZoneId.of("Asia/Tokyo"));
        System.out.println("ZonedDateTime - startDateTime: " + startDateTime);

        // Bieżąca data i czas z zegara systemowego z doklejoną strefą azjatycką - Tokio:
        ZonedDateTime localDtWithChangedZone  = ZonedDateTime.of(LocalDateTime.now(),
                                                                 ZoneId.of("Asia/Tokyo"));
        System.out.println("ZonedDateTime - startDateTimeLocalWithChangedZone: " + localDtWithChangedZone);

        // Bieżąca data i czas ze strefy amerykańskiej z doklejoną strefą azjatycką - Tokio:
        ZonedDateTime americanDtWithChangedZone  = ZonedDateTime.of(
                                                        LocalDateTime.now(ZoneId.of("America/Los_Angeles")),
                                                        ZoneId.of("Asia/Tokyo"));
        System.out.println("ZonedDateTime - startDateTimeAmericaWithChangedZone: " 
                                                                    + americanDtWithChangedZone);
    }
}
Wynik wykonania kodu:
Wynik wykonania kodu - ZonedDateTime
Appa Notka. Niech Cię nie zdziwi, że daty, które mają być identyczne, różnią się milisekundami. Wynika to z tego, że dla kolejnych przykładów na nowo pobieramy datę i czas za pomocą LocalDateTime.now(...) i podobnych metod, więc różnica milisekund pojawia się ze względu na delikatnie różny czas wykonania się tych linii kodu. Nie ma to znaczenia w kontekście tłumaczonych zagadnień.

Data w Java 8 - ZonedDateTime - dodatek

Na koniec rozdziału zerknij jeszcze na inne przykłady wykorzystania klasy ZonedDateTime. Najpierw różnymi metodami tworzymy dwie daty (zonedDateTime i startDateTime), które będą nam potrzebne nieco dalej. Następnie przekształcamy stringa na obiekt z datą. Charakterystyczne w tym stringu jest to, że uwzględniamy w nim offset (przesunięcie) oraz nazwę strefy czasowej.

Dalej wykorzystujemy metodę isBefore, której zadaniem jest sprawdzenie, czy data skonwertowana ze stringa jest przed bieżącą datą pobraną z zegara systemowego.

Ostatnie metody dokumentują, że tak jak było w przypadku LocalDateTime, tak samo i w przypadku ZonedDateTime możemy w łatwy sposób pobrać z obiektu daty poszczególne składowe czasu.
import java.time.ZoneId;
import java.time.ZonedDateTime;

public class Start {

    public static void main(String[] args) {

        // Bieżąca data i czas na podstawie zegara systemowego (domyślna strefa czasowa naszego systemu):
        ZonedDateTime zonedDateTime = ZonedDateTime.now();
        // Data i czas złożony z godziny, minut i sekund oraz nanosekund:
        ZonedDateTime startDateTime  = ZonedDateTime.of(2020, 6, 21, 20, 15, 30, 15,
                                                        ZoneId.of("Asia/Tokyo"));

        // Data i czas ze stringa ze strefą czasową:
        ZonedDateTime startDateTimeParsed = ZonedDateTime.parse("2020-04-21T20:15+02:00[Europe/Belgrade]");
        System.out.println("ZonedDateTime - startDateTimeParsed: " + startDateTimeParsed);

        // Porównanie dwóch dat z czasem - czy czas startDateTimeParsed jest przed czasem zonedDateTime:
        System.out.println("ZonedDateTime - isBefore:" + startDateTimeParsed.isBefore(zonedDateTime));

        // Pobranie godziny, minuty, sekundy oraz nanosekundy
        System.out.println("Hour: " + startDateTime.getHour());
        System.out.println("Minute: " + startDateTime.getMinute());
        System.out.println("Second: " + startDateTime.getSecond());
        System.out.println("Nano: " + startDateTime.getNano());
    }
}
Wynik wykonania kodu:
Wynik wykonania kodu - ZonedDateTime - dodatek
W rozdziale zajęliśmy się typami obiektów reprezentujących datę/czas w Javie 8. Pokazaliśmy też różnicę w stosunku do wcześniejszych wersji Javy. Na szczególne wyróżnienie zasługuje fakt udostępnienia odrębnych klas specjalizujących się w konkretnych zagadnieniach. Na tym etapie widać już, że mamy sporo nowych rozwiązań, a przecież wiele jeszcze przed nami. W kolejnym rozdziale zobaczysz, jak można wykorzystać potencjał klas Duration, Period oraz TemporalAdjusters. Nauczysz się także formatować daty za pomocą nowej klasy o nazwie DateTimeFormatter.
Zdjęcie autora
Autor: Jarek Klimas
Data: 03 stycznia 2024
Labele: Backend, Podstawowy, Java
Masz pytanie dotyczące tego rozdziału? Zadaj je nam!
Masz pytanie dotyczące prezentowanego materiału?
Coś jest dla Ciebie niejasne i Twoje wątpliwości przeszkadzają Ci w pełnym zrozumieniu treści?
Napisz do nas maila, a my chętnie znajdziemy odpowiednie rozwiązanie.
Najciekawsze pytania wraz z odpowiedziami będziemy publikować pod rozdziałem.
Nie czekaj. Naucz się programować jeszcze lepiej.
kursjava@javappa.com

Stale się rozwijamy, a więc bądź na bieżąco!
Na ten adres będziemy przesyłać informacje o ważniejszych aktualizacjach, a także o nowych materiałach pojawiających się na stronie.
Polub nas na Facebooku:
Nasi partnerzy: stackshare
Javappa to również profesjonalne usługi programistyczne oparte o technologie JAVA. Jeśli chesz nawiązać z nami kontakt w celu uzyskania doradztwa bądź stworzenia aplikacji webowej powinieneś poznać nasze doświadczenia.
Kliknij O nas .


Pozycjonowanie stron: Grupa TENSE