13. diel - Dátum a čas v Jave 8 - Parsovanie a porovnávanie
V minulej lekcii, Dátum a čas od Javy 8 - Úprava a intervaly , sme sa venovali prevedeniu, úprave hodnoty a časovým intervalom.
V dnešnom tutoriále sa pozrieme na čítanie hodnoty, parsovanie a porovnávanie.
Čítanie hodnoty
Hodnotu čítame pomocou metód začínajúcich na get*()
, tu
nás ani nič neprekvapí:
LocalDate halloween = LocalDate.of(2016, Month.OCTOBER, 31); System.out.println("Rok: " + halloween.getYear() + ", mesiac: " + halloween.getMonthValue() + ", deň: " + halloween.getDayOfMonth());
a výsledok:
Konzolová aplikácia
Rok: 2016, mesiac: 10, deň: 31
Všimnite si, že na získanie čísla mesiaca sme použili metódu
getMonthValue()
, pretože metóda getMonth()
by
vrátil hodnotu z výpočtového typu Month
.
Keby sme sa stretli so staršou triedou
Calendar
, musíme si dať pozor. Mesiace tam sú číslované od
0
namiesto od 1
, ako je to v triedach
LocalDate
/ LocalDateTime
.
Parsovanie dátumu a času
Dátum a čas budeme samozrejme často dostávať v textovej podobe, napr. od
používateľa z konzoly, zo súboru alebo z databázy. Asi tušíte, že na
vytvorenie LocalDateTime
z takejto textovej hodnoty použijeme
metódu parse()
priamo na dátovom type, ako to v Jave robíme
vždy.
Trieda LocalDate
predpokladá dátum vo formáte
yyyy-mm-dd
, trieda LocalDateTime
dátum a čas vo
formáte yyyy-mm-ddThh:mm:ss
a trieda LocalTime
čas
vo formáte hh:mm:ss
. Všetky čísla pred sebou musia mať nuly,
ak sú menšie ako 10
. Písmeno T
uprostred formátu
nie je preklep, ale naozaj oddelenie dátumu a času. To už môžeme vedieť z
predchádzajúcich lekcií. Skúsme si dátum 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)));
Nezabudneme 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ýsledok:
Konzolová aplikácia
8. 12. 2016 10:20:30
8. 12. 2016
10:20:30
Výsledok je samozrejme rôznorodý, záleží na lokalizácii systému. Preto môžete mať výstup iný.
Vlastný formát
Oveľa často budeme ale samozrejme chcieť naparzovať dátum a čas v
slovenskom tvare alebo v akomkoľvek inom tvare, východiskové oddeľovanie
dátumu a času pomocou písmena T
nie je práve 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ýsledok:
Konzolová aplikácia
8. 12. 2016 10:20:30
8. 12. 2016
10:20:30
Keby sme chceli treba špecifikovať vlastný formát v metóde
ofPattern()
a musel by formát obsahovať napríklad kľúčové
písmeno m
(normálne by to chcelo počet minút), môžeme ho
escapovať pomocou jednoduchých apostrofov '
. Skúsime naparzovať
naprí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á aplikácia
10:20:30
Porovnávanie inštancií
Pretože Java nepodporuje preťažovanie operátorov, porovnávame dátumy
(píšu schválne češtinsky nesprávne, dátami je v IT zavádzajúce slovo)
pomocou metód na to určených. Metódy začínajú na is*()
,
vymenujme si ich:
isAfter(datum)
- Vracia, či je inštancia za dátumom/dátom a časom odovzdávanej inštancie (či je hodnota väčšia).isBefore(datum)
- Vracia, či je inštancia pred dátumom/dátom a časom odovzdávanej inštancie (či je hodnota menšia).isEqual(datum)
- Vracia, či je inštancia nastavená na rovnaký dátum a/alebo čas ako je odovzdávaná inštancia (či je hodnota rovnaká).
is*()
,
uveďme si aj zvyšné dve:
isLeapYear()
- Vracia, či je inštancia nastavená na priestupný rok alebo nie.isSupported(ChronoUnit)
- Vracia, či inštancia podporuje prácu s danou chrono jednotkou (napr.LocalDate
nebude vedieťChronoUnit.HOURS
, pretože neobsahuje informáciu o čase).
LocalDate halloween = LocalDate.of(2016, 10, 31); LocalDate vanoce = LocalDate.of(2016, 12, 25); System.out.println("Halloween po Vianociach: " + halloween.isAfter(vanoce)); System.out.println("Halloween pred Vianocami: " + halloween.isBefore(vanoce)); System.out.println("zhodný Vianoce - Halloween: " + vanoce.isEqual(halloween)); System.out.println("zhodný Halloween - Halloween: " + halloween.isEqual(halloween)); System.out.println("priestupný rok 2016: " + halloween.isLeapYear()); System.out.println("priestupný 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 chýbajúci import:
import java.time.temporal.ChronoUnit;
Výsledok:
Konzolová aplikácia
Halloween po Vianociach: false
Halloween pred Vianocami:: true
zhodný Vianoce - Halloween: false
zhodný Halloween - Halloween: true
priestupný rok 2016: true
priestupný rok 2017: false
podporuje hodiny: false
podporuje roky: true
Ďalšie triedy
Okrem tried LocalDateTime
, LocalDate
a
LocalTime
sa môžeme stretnúť aj s niekoľkými ďalšími
triedami, ktoré využijeme skôr pri aplikáciách, ktoré sú na práci s
dátumom a časom založené. Nemusíme sa ich ľakať, vo väčšine prípadov
si vystačíme s triedou LocalDateTime
, ale mali by sme o nich mať
povedomie.
Instant
Trieda Instant
je pre dátum a čas, ale nie v poňatí
kalendára a prechodov na letný čas. Je to počet nanosekúnd od dátumu
1.1.1970
, teda jeden bod na časovej osi UTC
(univerzálneho času). Keď si kdekoľvek na Zemi napíšete aplikáciu s
týmto kódom:
Instant nyni = Instant.now(); System.out.println(nyni);
a importom:
import java.time.Instant;
Dostaneme na výstup vždy to isté, napríklad:
Konzolová aplikácia
2023-04-20T10:36:06.541863800Z
Trieda Instant
pozná len univerzálny čas a ten sa bude
líšiť od reálneho času v danej oblasti.
Triedy
OffsetDateTime
a ZonedDateTime
Už vieme, že Instant
je univerzálny čas a
LocalDateTime
má v sebe ten čas, ktorý je na danom území. Zo
samotného LocalDateTime
nedokážeme získať bod na univerzálnej
časovej osi, pretože nevieme na akom je území.
Čo nám chýba je teda kombinácia týchto dvoch, lokálne korektný čas,
ktorý by v sebe zároveň niesol informáciu o území (časovej zóne) a tým
pádom mohol byť univerzálne prevádzaný medzi rôznymi časovými zónami.
Práve na to slúži trieda ZonedDateTime
.
V Jave nájdeme aj triedu OffsetDateTim
, ktorá je taký
medzičlánok, ktorý umožňuje zaznamenať časový posun, ale nemá plnú
podporu zón.
Trieda ZoneId
Časové zóny sú v Jave reprezentované triedou ZoneId
. Poďme
si urobiť jednoduchú ukážku dátumu s časovou zónou:
ZonedDateTime lokalniDatumCas = ZonedDateTime.now(ZoneId.of("America/New_York"));
System.out.println(lokalniDatumCas);
Nezabudneme na potrebné balíčky:
import java.time.ZoneId; import java.time.ZonedDateTime;
Výstup:
Konzolová aplikácia
2017-02-02T06:37:11.026-05:00[America/New_York]
Áno, je to veľa tried, berme to skôr ako informácie, ku ktorým sa môžeme vrátiť až ich budeme potrebovať. Je dobré mať povedomie o tom, ako sa s dátumom pracuje. V Jave je tried vždy viac, než v ostatných jazykoch. Skúsme si vypestovať trpezlivosť a nejakú odolnosť voči tejto skutočnosti, zas sme kvôli tomu lepšie platení:) Nabudúce budeme zas chvíľu prakticky programovať, aby sme si od teórie oddýchli.
Epochy
Na úplný záver si poďme ešte predstaviť niekoľko posledných metód na
triede LocalDateTime
.
ofEpochSecond()
- Statická metóda nám umožňuje vytvoriť dátum a čas z tzv. Unix timestamp, v ktorom sa dátum a čas často ukladal najmä v minulosti. Je to veľké číslo označujúce počet sekúnd od dátumu1.1.1970
(začiatok unixovej epochy), musíme uviesť aj nanosekundy (väčšinou 0) a časovú zónu, čo je najčastejšieZoneOffset.UTC
. Metóda je dostupná aj na triedeLocalDate
ako metódaofEpochDay()
, kde prijíma počet dní namiesto sekúnd.toEpochSecond()
atoEpochDay()
- Metódy opačné k dvom predchádzajúcim, prevádza hodnotu na počet sekúnd/dní od roku1970
.
V nasledujúcom cvičení, Riešené úlohy k 12. lekcii OOP v Jave, si precvičíme nadobudnuté skúsenosti z predchádzajúcich lekcií.