13. diel - Dátum a čas od Javy 8 - Úprava a intervaly
V minulej lekcii, Dátum a čas v Jave 8 - Vytváranie a formátovanie, sme sa naučili vytvárať inštancie tried
LocalDate
, LocalTime
a LocalDateTime
a
formátovať ich hodnotu.
V dnešnom tutoriále sa budeme venovať úprave tejto hodnoty a zabehneme aj do časových intervalov.
Potrebné importy
Aby som zbytočne neopakoval, o aké importy v príkladoch ide, naimportujte si rovno všetky, ktoré použijeme:
import java.time.*; import java.time.format.DateTimeFormatter; import java.time.format.FormatStyle; import java.time.temporal.ChronoUnit; import java.time.temporal.TemporalAmount;
Prevody
Na úvod si ukážme, ako môžeme prevádzať medzi dátumami z inštancií
LocalDate
, LocalTime
a LocalDateTime
.
Prevod z LocalDateTime
Z dátumu LocalDateTime
prevádzame jednoducho pomocou jeho
metód toLocalDate()
a toLocalTime()
.
Prevod na LocalDateTime
Inštanciu LocalDateTime
vytvoríme pomocou jednej z
of()
metód, kde uvedieme zvlášť dátum a čas, napr. takto:
LocalDateTime dateTime = LocalDateTime.of(LocalDate.of(1939, 9, 1), LocalTime.of(10, 0)); // Setting the date to 9/1/1939 10:00 System.out.println(dateTime);
Výstup:
Konzolová aplikácia
1939-09-01T10:00
Ak chceme nastaviť čas na začiatok dňa, môžeme využiť metódu
atStartOfDay()
. Ďalšou metódou, ktorou môžeme vziať dátum a
pripojiť k nemu čas, je atTime()
. Pri tejto metóde si môžeme
nastaviť vlastnú hodinu a minútu. Ďalší variant príkladu vyššie by teda
bol:
LocalDate start = LocalDate.of(1939, 9, 1); LocalDateTime dayStart = start.atStartOfDay(); LocalDateTime selectedStart = start.atTime(10, 0); System.out.println(dayStart); System.out.println(selectedStart);
Na výstupe bude teda začiatok dňa (00:00 hodín) a ďalší čas bude o 10 hodine ako pri minulom príklade:
Konzolová aplikácia
1939-09-01T00:00
1939-09-01T10:00
Úprava hodnoty
K existujúcej inštancii môžeme pripočítať určitý počet dní, hodín
a podobne. Slúžia na to metódy začínajúce na plus...()
alebo
minus...()
, snáď netreba vysvetľovať, čo robia. Dôležitou
poznámkou je, že vracajú novú inštanciu s upravenou
hodnotou. Inštancia je vo všetkých ohľadoch
nemeniteľná (immutable
) a akákoľvek zmena
spočíta v nahradení za novú (napr. podobne ako to je v Jave s textovými
reťazcami).
Skúsme si to a pridajme aktuálnemu dátumu ďalšie 3 dni v týždni:
LocalDateTime dateTime = LocalDateTime.now();
dateTime = dateTime.plusDays(3);
System.out.println(dateTime.format(DateTimeFormatter.ofLocalizedDate(FormatStyle.MEDIUM)));
Ak si predstavíme, že dnes je 19.4.2023
, výstupom bude:
Konzolová aplikácia
22. 4. 2023
Metódy, ktoré máme k dispozícii, sú nasledovné:
minusDays()
minusHours()
minusMinutes()
minusMonths()
minusNanos()
- Odoberie z času nanosekundy.minusSeconds()
minusWeeks()
minusYears()
plusDays()
plusHours()
plusMinutes()
plusMonths()
plusNanos()
plusSeconds()
plusWeeks()
plusYears()
Do metód môžeme dávať aj záporné hodnoty. Ak zavoláme
napríklad metódu plusDays(-3)
, je táto metóda rovnaká ako
minusDays(3)
.
Triedy Period
a
Duration
Okrem vyššie spomenutých metód nájdeme aj 4 všeobecné verzie metód
minus()
a plus()
, ktoré prijímajú interval na
pridanie/odobratie. Využijeme ich najmä v prípade, kedy dopredu nevieme, či
budeme pridávať napr. dni alebo roky, ušetria nám veľa podmienkovania.
Máme k dispozícii triedy Duration
a Period
, na
ktorých si môžeme nechať vrátiť objekt reprezentujúci takýto
interval.
Až sa dostaneme k rozhraniam, môžete sa pozrieť, že obe
triedy implementujú spoločné rozhranie TemporalAmount
. Zatiaľ
si s nimi však nemotajme hlavu.
Upravený kód nášho príkladu by vyzeral takto:
LocalDateTime dateTime = LocalDateTime.now();
dateTime = dateTime.plus(Period.ofDays(3));
System.out.println(dateTime.format(DateTimeFormatter.ofLocalizedDate(FormatStyle.MEDIUM)));
Výstup bude rovnaký, ako pri príklade vyššie. of...()
metódy majú rovnaké "prípony" ako mali plus/mínus metódy vymenované
vyššie:
Konzolová aplikácia
22. 4. 2023
Trieda Duration
na rozdiel od triedy Period
označuje nejaký časový interval, ktorý vôbec nesúvisí s kalendárom
(napr. ako dlho trvá vyrobiť automobil), deň trvá vždy 24 hodín. Trieda
Period
počíta s prechodom na letný čas, deň teda môže
niekedy trvať 23 alebo 25 hodín. Period
použijeme pri práci s
triedami LocalDate
/ LocalDateTime
, triedu
Duration
pri práci s časom.
Trieda ChronoUnit
Pre ľahšiu prácu s rôznymi jednotkami ako sú dni, hodiny, minúty a
podobne je nám k dispozícii trieda ChronoUnit
. Vnútorne
používa triedu Duration
. Ide teda iba o iný zápis už
predchádzajúcich úloh, ale len pre istotu, ak by ste sa s ním niekedy
stretli, ukážme si ho:
LocalDateTime dateTime = LocalDateTime.now();
dateTime = dateTime.plus(3, ChronoUnit.DAYS);
System.out.println(dateTime.format(DateTimeFormatter.ofLocalizedDate(FormatStyle.MEDIUM)));
Len pre úplnosť dodajme, že trieda ChronoUnit
implementuje rozhranie TemporalUnit
, keby ste sa s ním neskôr
stretli. Teraz rozhranie riešiť nebudeme.
Ako môžeme vidieť, implementácia dátumu a času je v Jave pomerne zložitá, nebudeme tu zabiehať do zbytočných detailov a zameriame sa najmä na praktickú stránku použitia, ako to u nás na sieti väčšinou robíme.
Ďalšie metódy
Ukážme si ešte ďalšie užitočné metódy.
Metóda between()
Ďalšia metóda, ktorú máme k dispozícii, je statická metóda
between()
na triede Period
, ktorá nám umožňuje
získať interval, teda rozdiel medzi 2 dátumami (presnejšie objekty s
rozhraním Temporal
, to je spoločný typ pre triedy
LocalDate
, LocalDateTime
a
LocalTime
):
LocalDate started = LocalDate.of(1939, 9, 1); LocalDate ended = LocalDate.of(1945, 9, 2); TemporalAmount period = Period.between(started, ended); System.out.println("The World War II lasted for " + period.get(ChronoUnit.YEARS) + " years and " + period.get(ChronoUnit.DAYS) + " days");
Výstup:
Konzolová aplikácia
The World War II lasted for 6 years and 1 days
Tú istú metódu nájdeme aj na triede Duration
, tu však
pracuje s triedou LocalDateTime
namiesto triedy
LocalDate
. Z intervalu nezistíme počet rokov, pretože roky
nemajú pevný počet dní a my už vieme, že Duration
nie je
nijako spojená s kalendárnym poňatím času.
Metóda until()
Ako posledná stojí za zmienku metóda until()
. Táto metóda
sa volá priamo nad inštanciami tried LocalDate
,
LocalDateTime
a LocalTime
a vracia rovnaký výsledok,
ako statická metóda between()
.
LocalDate started = LocalDate.of(1939, 9, 1); LocalDate ended = LocalDate.of(1945, 9, 2); // Period between 9/1/1939 and 9/2/1945 Period period = started.until(ended); System.out.println("The World War II lasted for " + period.get(ChronoUnit.YEARS) + " years and " + period.get(ChronoUnit.DAYS) + " days");
Výstup je rovnaký:
Konzolová aplikácia
The World War II lasted for 6 years and 1 days
Nastavenie hodnoty
Hodnotu nastavujeme pomocou metód with...*()
, majú opäť tie
isté "prípony" ako metódy doposiaľ spomínané. Ako vždy nezabudnite, že
ako všetky podobné metódy vracajú novú inštanciu:
LocalDateTime started = LocalDateTime.of(1939, 9, 1, 0, 0); started = started.withHour(10); // Sets the hour to 10
Reťazenie metód
Vrátenie nových inštancií, ktoré je najmä výsledkom toho, že sú inštancie immutable, zároveň poskytuje tzv. fluent interface (slovensky niekedy prekladané ako plynulé rozhranie). Jedná sa o reťazenie metód, anglicky method chaining. Nehľadajte v tom žiadnu zložitosť, ide len o to, že môžeme väčšinu metód volať po sebe na jednom riadku.
Skúsme si nastaviť kalendár na programátorské vianoce, teda na Halloween (áno, pretože Oct 31 = Dec 25):
LocalDate started = LocalDate.of(1939, 9, 1); started = started.withMonth(10).withDayOfMonth(31);
V budúcej lekcii, Dátum a čas v Jave 8 - Parsovanie a porovnávanie, sa pozrieme na parsovanie a porovnávanie dátumu a času.