Java 8 #6: daty i czas (nowe DateTime API)

Nie rzadko w Twojej implementacji będziesz korzystał z danych, które będą wymagać przypisania do nich odpowiednich wartości dat czy czasu. Do JDK w wersji 7 programiści Java byli zmuszeni do korzystania z prostych i mało udanych implementacji zawartych w klasach Date i Calendar. Największe wyzwania jakie stały przed twórcami nowego DateTime API było:

  • stworzenie prostego, przyjaznego API do programisty
  • praca w środowisku wielowątkowym
  • programowanie systemów działających w wielu strefach czasowych

LocalDate vs LocalTime vs LocalDateTime

Wszystkie trzy nowe klasy działają bardzo podobnie. Główną różnicą jest to, że jak sama nazwa wskazuje, jedna z nich odnosi się tylko do daty, następna do czasu, a ostatnia pracuje na wartościach zawierających zarówno czas jak i datę.

Najpierw pokażę Ci co potrafi samo LocalDate.

IntStream stream = IntStream.range(1, 10);
stream.forEach(i -> {
	LocalDate date = LocalDate.of(2010 + i, Month.JANUARY, 1);
	System.out.println(date.getDayOfWeek());
});

Pierwszą ważną kwestią wartą wyjaśnienia jest nowy rodzaj strumieni, omawianych dokładniej w lekcji poprzedniej*. Klasa IntStream umożliwia w łatwy sposób tworzenie strumieni liczb całkowitych. W ten też sposób można wygodnie iterować unikając klasycznej pętli for. W samej pętli forEach, został utworzony obiekt date, który za pomocą metody of(), utworzy instancję klasy LocalDate w zależności od atrybutów, wypełnionych przez Ciebie w konstruktorze (są to odpowiednio: rok, miesiąc, dzień). W moim przypadku będzie to zawsze pierwszy dzień stycznia z zakresu lat 2010 – 2020. Na koniec wyświetlam dzień tygodnia, wykreowanej przeze mnie daty (oczywiście będzie to nazwa anglojęzyczna).

Efekt na konsoli:

SATURDAY
SUNDAY
TUESDAY
WEDNESDAY
THURSDAY
FRIDAY
SUNDAY
MONDAY
TUESDAY

Teraz pobawię się klasą LocalTime.

LocalTime localTime = LocalTime.now();
System.out.println("Actual time is: " + localTime + ", 10 hours before was: " + localTime.minusHours(10));

Korzystając z metody now() utworzyłem obiekt LocalDate, który reprezentuje aktualną datę w Twoim komputerze. API tej klasy, podobnie jak w poprzednim przykładzie udostępnia wiele przydatnych metod ułatwiających jej manipulację. W moim przykładzie skorzystałem z metody minusHours, aby wyświetlić datę o dziesięć godzin wcześniejszą. Tego typu metod jest o wiele więcej, ale z oczywistych względów nie będę ich wszystkich omawiał. Jeśli chcesz przejrzeć je wszystkie, jak zawsze polecam oficjalną dokumentację**.

Na koniec skorzystam z API LocalDateTime. Jest ono praktycznie takie samo jak w przypadku LocalTime, dlatego w tym przykładzie pokażę Ci inną ciekawą metodę query, dzięki której możesz wyciągać interesujące Cię fragmenty obiektu, poprzez użycie odpowiedniego zapytania.

LocalDateTime localDateTime = LocalDateTime.now();
System.out.println("Actual date is: " + localDateTime.query(TemporalQueries.localDate()));
System.out.println("Actual time is: " + localDateTime.query(TemporalQueries.localTime()));

W tym przypadku skorzystano z gotowych „zapytań” zawartych w klasie pomocniczej TemporalQueries.

ZonedDateTime

Czasami jednak potrzebujesz do pracy konstrukcji pozwalającej na łatwe przetwarzanie aktualnej daty z jednej strefy czasowej do innej. Bardzo sprawnie zadziała tu klasa ZonedDateTime. Pewnym problemem może być wskazanie odpowiedniej nazwy pożądanej strefy czasowej, używanej w konstruktorze. Wynika to z tego, że jak się domyślasz, jest ich naprawdę dużo. Dlatego też do pomocy wykorzystam obiekt ZoneId, za pomocą którego łatwo sprawdzić, które strefy czasowe w jaki sposób zostały nazwane.

ZoneId.getAvailableZoneIds().stream()
        .filter(name -> name.contains("Europe"))
        .map(id -> ZoneId.of(id))
        .forEach(x -> System.out.println(LocalDateTime.now().atZone(x)));

Powyższy kod wyświetli wszystkie strefy czasowe w Europie. Znając nazwy stref czasowych można utworzyć obiekt ZonedDateTime na kilka sposób. Pierwsza opcja to wpisanie danych daty i czasu manualnie, drugą możliwością jest użycie metody now podobnie jak w przypadku klasy LocalDate, trzecią skorzystanie z obiektu LocalDateTime. Ostatnia możliwość to sparsowanie Stringa, zawierającego odpowiednie dane. Jest to o tyle niewdzwięczne zadanie, że jedna literówka doprowadzi do wyrzucenia wyjątku DateTimeParseException.

ZonedDateTime zonedDateTime = ZonedDateTime.of(2021, 07, 31, 21, 31, 0, 0, ZoneId.of("Europe/Warsaw"));
ZonedDateTime zonedDateTimeNow = ZonedDateTime.now(ZoneId.of("Europe/Warsaw"));
ZonedDateTime zonedDateTimeFromLocal = ZonedDateTime.of(LocalDateTime.now(), ZoneId.of("Europe/Warsaw"));
ZonedDateTime zonedDateTimeParsed =  ZonedDateTime.parse("2021-07-31T21:31+02:00[Europe/Warsaw]");
		
System.out.println("ZonedDatetime created from of method " + zonedDateTime + 
	"\nzonedDateTimeused now method " + zonedDateTimeNow +
	"\nzonedDateTime created from from localDateTime " + zonedDateTimeFromLocal +
	"\nzonedDateTime parsed from String " + zonedDateTimeParsed);

Samo API ZonedDateTime jest bardzo podobne do API LocalDateTime, także nie będę się nad nim dłużej rozwodził.

Konwersja ze starego zapisu

Czasami niestety będziesz pracować z kodem zastanym, który będzie zawierać datę i kalendarz. Na szczęście konwersja poprzednich obiektów do nowych nie stanowi wielkiego problemu.

Calendar calendar = Calendar.getInstance();
Date date =  calendar.getTime();
System.out.println(LocalDateTime.ofInstant(date.toInstant(), ZoneId.systemDefault()));
System.out.println(LocalDateTime.ofInstant(calendar.toInstant(), ZoneId.systemDefault()));

To wszystko jeśli chodzi o pracę z datą i czasem w Javie 8+. Co więcej jest to ostatnia lekcja z kursu Java 8. Jeśli tu udało Ci się dotrzeć, to gratuluję! Znasz już najpopularniejszą obecnie wersję JDK.

*Lekcja o Stream API: Java 8 #5: zastosowanie Stream API w przetwarzaniu danych

**Dokumentacja do nowego Date API:

https://docs.oracle.com/javase/8/docs/api/java/time/LocalTime.html

https://docs.oracle.com/javase/8/docs/api/java/time/LocalDate.html

https://docs.oracle.com/javase/8/docs/api/java/time/LocalDateTime.html

Kod do lekcji: https://github.com/developeronthego/java-jdk8/tree/master/src/main/java/java8/datetime

Może Ci się również spodoba

Dodaj komentarz

Twój adres e-mail nie zostanie opublikowany. Wymagane pola są oznaczone *