Vydělávej až 160.000 Kč měsíčně! Akreditované rekvalifikační kurzy s garancí práce od 0 Kč. Více informací.
Hledáme nové posily do ITnetwork týmu. Podívej se na volné pozice a přidej se do nejagilnější firmy na trhu - Více informací.

Lekce 14 - Datum a čas v Javě 8 - Parsování a porovnávání

V minulé lekci, Datum a čas od Javy 8 - Úprava a intervaly, jsme se věnovali převedení, úpravě hodnoty a časovým intervalům.

V dnešním tutoriálu se podíváme na čtení hodnoty, parsování a porovnávání.

Čtení hodnoty

Hodnotu čteme pomocí metod začínajících na get*(), zde nás ani nic nepřekvapí:

LocalDate halloween = LocalDate.of(2016, Month.OCTOBER, 31);
System.out.println("Rok: " + halloween.getYear() + ", měsíc: " + halloween.getMonthValue() + ", den: " + halloween.getDayOfMonth());

a výsledek:

Konzolová aplikace
Rok: 2016, měsíc: 10, den: 31

Všimněte si, že pro získání čísla měsíce jsme použili metodu getMonthValue(), protože metoda getMonth() by vrátil hodnotu z výčtového typu Month.

Kdybychom se setkali se starší třídou Calendar, musíme si dát pozor. Měsíce tam jsou číslované od 0 místo od 1, jak je tomu ve třídách LocalDate/LocalDateTime.

Parsování data a času

Datum a čas budeme samozřejmě často dostávat v textové podobě, např. od uživatele z konzole, ze souboru nebo z databáze. Asi tušíte, že k vytvoření LocalDateTime z takovéto textové hodnoty použijeme metodu parse() přímo na datovém typu, jako to v Javě děláme vždy.

Třída LocalDate předpokládá datum ve formátu yyyy-mm-dd, třída LocalDateTime datum a čas ve formátu yyyy-mm-ddThh:mm:ss a třída LocalTime čas ve formátu hh:mm:ss. Všechna čísla před sebou musí mít nuly, pokud jsou menší jak 10. Písmeno T uprostřed formátu není překlep, ale opravdu oddělení data a času. To už můžeme vědět z předchozích lekcí. Zkusme si datum a čas :

LocalDateTime datumCas = LocalDateTime.parse("2016-12-08T10:20:30");
LocalDate datum = LocalDate.parse("2016-12-08");
LocalTime cas = LocalTime.parse("10:20:30");

System.out.println(datumCas.format(DateTimeFormatter.ofLocalizedDateTime(FormatStyle.MEDIUM)));
System.out.println(datum.format(DateTimeFormatter.ofLocalizedDate(FormatStyle.MEDIUM)));
System.out.println(cas.format(DateTimeFormatter.ofLocalizedTime(FormatStyle.MEDIUM)));

Nezapomeneme zase na importy:

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.time.format.FormatStyle;

Možný výsledek:

Konzolová aplikace
8. 12. 2016 10:20:30
8. 12. 2016
10:20:30

Výsledek je samozřejmě různorodý, záleží na lokalizaci systému. Proto můžete mít výstup jiný.

Vlastní formát

Mnohem často budeme ale samozřejmě chtít naparsovat datum a čas v českém tvaru nebo v jakémkoli jiném tvaru, výchozí oddělování data a času pomocí písmene T není zrovna user-friendly :)

LocalDateTime datumCas = LocalDateTime.parse("12/08/2016 10:20:30", DateTimeFormatter.ofPattern("M/d/y HH:mm:ss"));
LocalDate datum = LocalDate.parse("12/8/2016", DateTimeFormatter.ofPattern("M/d/y"));
LocalTime cas = LocalTime.parse("10:20:30", DateTimeFormatter.ofPattern("H:m:ss"));

System.out.println(datumCas.format(DateTimeFormatter.ofLocalizedDateTime(FormatStyle.MEDIUM)));
System.out.println(datum.format(DateTimeFormatter.ofLocalizedDate(FormatStyle.MEDIUM)));
System.out.println(cas.format(DateTimeFormatter.ofLocalizedTime(FormatStyle.MEDIUM)));

Výsledek:

Konzolová aplikace
8. 12. 2016 10:20:30
8. 12. 2016
10:20:30

Kdybychom chtěli třeba specifikovat vlastní formát v metodě ofPattern() a musel by formát obsahovat například klíčové písmeno m (normálně by to chtělo počet minut), můžeme ho escapovat pomocí jednoduchých apostrofů '. Zkusíme naparsovat například 10h:20m:30s:

LocalTime cas = LocalTime.parse("10h:20m:30s", DateTimeFormatter.ofPattern("H'h':m'm':ss's'"));
System.out.println(cas);

Výstup:

Konzolová aplikace
10:20:30

Porovnávání instancí

Protože Java nepodporuje přetěžování operátorů, porovnáváme datumy (píší schválně češtinsky nesprávně, daty je v IT zavádějící slovo) pomocí metod k tomu určených. Metody začínají na is*(), vyjmenujme si je:

  • isAfter(datum) - Vrací, zda je instance za datem/datem a časem předávané instance (zda je hodnota větší).
  • isBefore(datum) - Vrací, zda je instance před datem/datem a časem předávané instance (zda je hodnota menší).
  • isEqual(datum) - Vrací, zda je instance nastavena na stejný datum a/nebo čas jako je předávaná instance (zda je hodnota stejná).

To bylo jednoduché, že? Když už jsme u metod is*(), uveďme si i zbývající dvě:

  • isLeapYear() - Vrací, zda je instance nastavena na přestupný rok či nikoli.
  • isSupported(ChronoUnit) - Vrací, zda instance podporuje práci s danou chrono jednotkou (např. LocalDate nebude umět ChronoUnit.HOURS, protože neobsahuje informaci o čase).

Ukažme si příklad:

LocalDate halloween = LocalDate.of(2016, 10, 31);
LocalDate vanoce = LocalDate.of(2016, 12, 25);
System.out.println("Halloween po Vánocích: " + halloween.isAfter(vanoce));
System.out.println("Halloween před Vánocemi: " + halloween.isBefore(vanoce));
System.out.println("shodný Vánoce - Halloween: " + vanoce.isEqual(halloween));
System.out.println("shodný Halloween - Halloween: " + halloween.isEqual(halloween));
System.out.println("přestupný rok 2016: " + halloween.isLeapYear());
System.out.println("přestupný rok 2017: " + halloween.withYear(2017).isLeapYear());
System.out.println("podporuje hodiny: " + halloween.isSupported(ChronoUnit.HOURS));
System.out.println("podporuje roky: " + halloween.isSupported(ChronoUnit.YEARS));

Doplníme chybějící import:

import java.time.temporal.ChronoUnit;

Výsledek:

Konzolová aplikace
Halloween po Vánocích: false
Halloween před Vánocemi:: true
shodný Vánoce - Halloween: false
shodný Halloween - Halloween: true
přestupný rok 2016: true
přestupný rok 2017: false
podporuje hodiny: false
podporuje roky: true

Další třídy

Kromě tříd LocalDateTime, LocalDate a LocalTime se můžeme setkat také s několika dalšími třídami, které využijeme spíše u aplikací, které jsou na práci s datem a časem založené. Nemusíme se jich lekat, ve většině případů si vystačíme s třídou LocalDateTime, ale měli bychom o nich mít povědomí.

Instant

Třída Instant je pro datum a čas, ale ne v pojetí kalendáře a přechodů na letní čas. Je to počet nanosekund od data 1.1.1970, tedy jeden bod na časové ose UTC (univerzálního času). Když si kdekoli na Zemi napíšete aplikaci s tímto kódem:

Instant nyni = Instant.now();
System.out.println(nyni);

a importem:

import java.time.Instant;

Dostaneme na výstup vždy to samé, například:

Konzolová aplikace
2023-04-20T10:36:06.541863800Z

Třída Instant zná jen univerzální čas a ten se bude lišit od reálného času v dané oblasti.

Třídy OffsetDateTime a ZonedDateTime

Již víme, že Instant je univerzální čas a LocalDateTime má v sobě ten čas, který je na daném území. Ze samotného LocalDateTime nedokážeme získat bod na univerzální časové ose, protože nevíme na jakém je území.

Co nám chybí je tedy kombinace těchto dvou, lokálně korektní čas, který by v sobě zároveň nesl informaci o území (časové zóně) a tím pádem mohl být univerzálně převáděn mezi různými časovými zónami. Právě k tomu slouží třída ZonedDateTime.

V Javě nalezneme také třídu OffsetDateTim, která je takový mezičlánek, který umožňuje zaznamenat časový posun, ale nemá plnou podporu zón.

Třída ZoneId

Časové zóny jsou v Javě reprezentovány třídou ZoneId. Pojďme si udělat jednoduchou ukázku datumu s časovou zónou:

ZonedDateTime lokalniDatumCas = ZonedDateTime.now(ZoneId.of("America/New_York"));
System.out.println(lokalniDatumCas);

Nezapomeneme na potřebné balíčky:

import java.time.ZoneId;
import java.time.ZonedDateTime;

Výstup:

Konzolová aplikace
2017-02-02T06:37:11.026-05:00[America/New_York]

Ano, je to hodně tříd, berme to spíše jako informace, ke kterým se můžeme vrátit až je budeme potřebovat. Je dobré mít povědomí o tom, jak se s datumem pracuje. V Javě je tříd vždy více, než v ostatních jazycích. Zkusme si vypěstovat trpělivost a nějakou odolnost vůči této skutečnosti, zas jsme kvůli tomu lépe placení :) Příště budeme zas chvíli prakticky programovat, abychom si od teorie odpočinuli.

Epochy

Na úplný závěr si pojďme ještě představit několik posledních metod na třídě LocalDateTime.

  • ofEpochSecond() - Statická metoda nám umožňuje vytvořit datum a čas z tzv. Unix timestamp, ve kterém se datum a čas často ukládal zejména v minulosti. Je to velké číslo označující počet vteřin od datumu 1.1.1970 (začátek unixové epochy), musíme uvést i nanosekundy (většinou 0) a časovou zónu, což je nejčastěji ZoneOffset.UTC. Metoda je dostupná i na třídě LocalDate jako metoda ofEpochDay(), kde přijímá počet dní místo sekund.
  • toEpochSecond() a toEpochDay() - Metody opačné ke dvěma předchozím, převádí hodnotu na počet sekund/dní od roku 1970.

To je k datu a času od Javy verze 8 opravdu vše.

V následujícím cvičení, Řešené úlohy k 12. lekci OOP v Javě, si procvičíme nabyté zkušenosti z předchozích lekcí.


 

Předchozí článek
Datum a čas od Javy 8 - Úprava a intervaly
Všechny články v sekci
Objektově orientované programování v Javě
Přeskočit článek
(nedoporučujeme)
Řešené úlohy k 12. lekci OOP v Javě
Článek pro vás napsal David Hartinger
Avatar
Uživatelské hodnocení:
381 hlasů
David je zakladatelem ITnetwork a programování se profesionálně věnuje 15 let. Má rád Nirvanu, nemovitosti a svobodu podnikání.
Unicorn university David se informační technologie naučil na Unicorn University - prestižní soukromé vysoké škole IT a ekonomie.
Aktivity