IT rekvalifikace s garancí práce. Seniorní programátoři vydělávají až 160 000 Kč/měsíc a rekvalifikace je prvním krokem. Zjisti, jak na to!
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 13 - Datum a čas od Javy 8 - Úprava a intervaly

V minulé lekci, Datum a čas v Javě 8 - Vytváření a formátování, jsme se naučili vytvářet instance tříd LocalDate, LocalTime a LocalDateTime a formátovat jejich hodnotu.

V dnešním tutoriálu se budeme věnovat úpravě této hodnoty a zaběhneme i do časových intervalů.

Potřebné importy

Abych zbytečně neopakoval, o jaké importy v příkladech jde, naimportujte si je rovnou všechny, které 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;

Převody

Na úvod si ukažme, jak můžeme převádět mezi datumy z instancí LocalDate, LocalTime a LocalDateTime.

Převod z LocalDateTime

Z datumu LocalDateTime převádíme jednoduše pomocí jeho metod toLocalDate() a toLocalTime().

Převod na LocalDateTime

Instanci LocalDateTime vytvoříme pomocí jedné z of() metod, kde uvedeme zvlášť datum a čas, např. takto:

LocalDateTime datumCas = LocalDateTime.of(LocalDate.of(1939, 9, 1), LocalTime.of(10, 0)); // nastavíme datum 1.9.1939 a 10. hodinu
System.out.println(datumCas);

Výstup:

Konzolová aplikace
1939-09-01T10:00

Pokud chceme nastavit čas na začátek dne, můžeme využít metody atStartOfDay(). Další metodou, kterou můžeme vzít datum a připojit k němu čas, je atTime(). U této metody si můžeme nastavit vlastní hodinu a minutu. Další varianta příkladu výše by tedy byla:

LocalDate zacatek = LocalDate.of(1939, 9, 1);
LocalDateTime zacatekDne = zacatek.atStartOfDay();
LocalDateTime danyZacatek = zacatek.atTime(10, 0);
System.out.println(zacatekDne);
System.out.println(danyZacatek);

Na výstupu bude tedy začátek dne (00:00 hodin) a další čas bude v 10 hodin jako u minulého příkladu:

Konzolová aplikace
1939-09-01T00:00
1939-09-01T10:00

Úprava hodnoty

K existující instanci můžeme přičítat určitý počet dní, hodin a podobně. Slouží k tomu metody začínající na plus...() nebo minus...(), snad netřeba vysvětlovat co dělají. Důležitá poznámka je, že vracejí novou instanci s upravenou hodnotou. Instance je ve všech ohledech neměnitelná (immutable) a jakákoli změna spočítá v nahrazení za novou (např. podobně jako to je v Javě s textovými řetězci).

Zkusme si to a přidejme aktuálnímu datu další 3 dny v týdnu:

LocalDateTime datumCas = LocalDateTime.now();
datumCas = datumCas.plusDays(3);
System.out.println(datumCas.format(DateTimeFormatter.ofLocalizedDate(FormatStyle.MEDIUM)));

Pokud si představíme, že je dnes 19.4.2023, výstupem bude:

Konzolová aplikace
22. 4. 2023

Metody, které máme k dispozici, jsou následující:

  • minusDays()
  • minusHours()
  • minusMinutes()
  • minusMonths()
  • minusNanos() - Odebere z času nanosekundy.
  • minusSeconds()
  • minusWeeks()
  • minusYears()
  • plusDays()
  • plusHours()
  • plusMinutes()
  • plusMonths()
  • plusNanos()
  • plusSeconds()
  • plusWeeks()
  • plusYears()

Do metod můžeme dávat i záporné hodnoty. Pokud zavoláme například metodu plusDays(-3), je tato metoda stejná jako minusDays(3).

Třídy Period a Duration

Kromě výše zmíněných metod nalezneme i 4 obecné verze metod minus() a plus(), které přijímají interval k přidání/odebrání. Využijeme je zejména v případě, kdy dopředu nevíme, zda budeme přidávat např. dny nebo roky, ušetří nám spoustu podmínkování. Máme k dispozici třídy Duration a Period, na kterých si můžeme nechat vrátit objekt reprezentující takový interval.

Až se dostaneme k rozhraním, můžete se podívat, že obě třídy implementující společné rozhraní TemporalAmount. Zatím si s nimi však nemotejme hlavu.

Upravený kód našeho příkladu by vypadal takto:

LocalDateTime datumCas = LocalDateTime.now();
datumCas = datumCas.plus(Period.ofDays(3));
System.out.println(datumCas.format(DateTimeFormatter.ofLocalizedDate(FormatStyle.MEDIUM)));

Výstup bude stejný, jako u příkladu výše. of...() metody mají stejné "přípony" jako měly plus/minus metody vyjmenované výše>

Konzolová aplikace
22. 4. 2023

Třída Duration na rozdíl od třídy Period označuje nějaký časový interval, který vůbec nesouvisí s kalendářem (např. jak dlouho trvá vyrobit automobil), den trvá vždy 24 hodin. Třída Period počítá s přechodem na letní čas, den tedy může někdy trvat 23 nebo 25 hodin. Period použijeme při práci s třídami LocalDate/LocalDateTime, třídu Duration při práci s časem.

Třída ChronoUnit

Pro snazší práci s různými jednotkami jako jsou dny, hodiny, minuty a podobně je nám k dispozici třída ChronoUnit. Vnitřně používá třídu Duration. Jedná se tedy pouze o jiný zápis již předchozích úloh, ale jen pro jistotu, kdybyste jej někdy potkali, ukažme si jej:

LocalDateTime datumCas = LocalDateTime.now();
datumCas = datumCas.plus(3, ChronoUnit.DAYS);
System.out.println(datumCas.format(DateTimeFormatter.ofLocalizedDate(FormatStyle.MEDIUM)));

Jen pro úplnost si dodejme, že třída ChronoUnit implementuje rozhraní TemporalUnit, kdybyste se s ním později setkali. Nyní rozhraní řešit nebudeme.

Jak můžeme vidět, implementace data a času je v Javě poměrně složitá, nebudeme tu zabíhat do zbytečných detailů a zaměříme se zejména na praktickou stránku použití, jak to u nás na síti většinou děláme.

Další metody

Ukažme si ještě další užitečné metody.

Metoda between()

Další metoda, kterou máme k dispozici, je statická metoda between() na třídě Period, která nám umožňuje získat interval, tedy rozdíl mezi 2 datumy (přesněji objekty s rozhraním Temporal, to je společný typ pro třídy LocalDate, LocalDateTime a LocalTime):

LocalDate zacatek = LocalDate.of(1939, 9, 1);
LocalDate konec = LocalDate.of(1945, 9, 2);
TemporalAmount doba = Period.between(zacatek, konec);
System.out.println("II. světová válka trvala " + doba.get(ChronoUnit.YEARS) + " let a " + doba.get(ChronoUnit.DAYS) + " dní");

Výstup:

Konzolová aplikace
II. světová válka trvala 6 let a 1 dní

Tu samou metodu nalezneme i na třídě Duration, která ovšem pracuje s třídou LocalDateTime místo třídy LocalDate. Z intervalu nezjistíme počet let, protože roky nemají pevný počet dnů a my již víme, že Duration není nijak spojená s kalendářním pojetím času.

Metoda until()

Jako poslední stojí za zmínku metoda until(). Tato metoda se volá přímo nad instancemi tříd LocalDate, LocalDateTime a LocalTime a vrací stejný výsledek, jako statická metoda between().

LocalDate zacatek = LocalDate.of(1939, 9, 1);
LocalDate konec = LocalDate.of(1945, 9, 2);
// Doba mezi datumy 1.9.1939 a 2.9.1945
Period doba = zacatek.until(konec);
System.out.println("II. světová válka trvala " + doba.get(ChronoUnit.YEARS) + " let a " + doba.get(ChronoUnit.DAYS) + " dní");

Výstup je stejný:

Konzolová aplikace
II. světová válka trvala 6 let a 1 dní

Nastavení hodnoty

Hodnotu nastavujeme pomocí metod with...*(), mají opět ty samé "přípony" jako metody doposud zmíněné. Jako vždy nezapomeňte, že jako všechny podobné metody vracejí novou instanci:

LocalDateTime zacatek = LocalDateTime.of(1939, 9, 1, 0, 0);
zacatek = zacatek.withHour(10); // Nastaví na 10. hodinu

Řetězení metod

Vracení nových instancí, které je zejména výsledkem toho, že jsou instance immutable, zároveň poskytuje tzv. fluent interface (česky někdy překládané jako plynulé rozhraní). Jedná se o řetězení metod, anglicky method chaining. Nehledejte v tom žádnou složitost, jde jen o to, že můžeme většinu metod volat po sobě na jednom řádku.

Zkusme si nastavit kalendář na programátorské vánoce, tedy na Halloween (ano, protože Oct 31 = Dec 25):

LocalDate zacatek = LocalDate.of(1939, 9, 1);
zacatek = zacatek.withMonth(10).withDayOfMonth(31);

V příští lekci, Datum a čas v Javě 8 - Parsování a porovnávání, se podíváme na parsování a porovnávání datumu a času.


 

Předchozí článek
Datum a čas v Javě 8 - Vytváření a formátování
Všechny články v sekci
Objektově orientované programování v Javě
Přeskočit článek
(nedoporučujeme)
Datum a čas v Javě 8 - Parsování a porovnávání
Článek pro vás napsal David Hartinger
Avatar
Uživatelské hodnocení:
416 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