Lekce 13 - Datum a čas v Kotlin - Parsování a porovnávání
V minulé lekci, Datum a čas v Kotlin - Úprava a intervaly, jsme se věnovali převedení, úpravě hodnoty a časovým intervalům.
V dnešním Kotlin tutoriálu dokončíme téma data a času. Podíváme se na čtení hodnoty, parsování a porovnávání.
Čtení hodnoty
Hodnotu čteme pomocí vlastností, zde nás ani nic nepřekvapí:
{KOTLIN_OOP}
import java.time.LocalDate
import java.time.LocalDateTime
import java.time.LocalTime
import java.time.Month
import java.time.format.DateTimeFormatter
import java.time.format.FormatStyle
fun main(args: Array<String>) {
val halloween = LocalDate.of(2016, Month.OCTOBER, 31)
println("Rok: " + halloween.year + ", měsíc: " + halloween.monthValue + ", den: " + halloween.dayOfMonth)
}
{/KOTLIN_OOP}
Všimněte si, že když nám IntelliJ radí (pomocí Ctrl + Space), tak se po levé straně zobrazují javovské názvy metod, které jsou přegenerované do vlastností Kotlinem, pro snazší práci (to v závorce, šedým písmem).

A výsledek:
Rok: 2016, měsíc: 10, den: 31
Všimněte si, že pro získání čísla měsíce jsme použili
monthValue
, protože month
by vrátil hodnotu z
výčtového typu Month
.
Pokud se setkáte se starší třídou Calendar
,
dejte si pozor, protože tam jsou měsíce číslované od 0
místo
od 1
, jak je tomu v
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 Kotlinu děláme
vždy.
Ta výchozí předpokládá datum ve formátu yyyy-mm-dd
, datum
a čas ve formátu yyyy-mm-ddThh:mm:ss
a čas ve formátu
hh:mm:ss
. Všechna čísla před sebou musí mít nuly, pokud jsou
menší jak 10. T
není překlep, ale opravdu oddělení data a
času. Zkusme si to:
{KOTLIN_OOP}
import java.time.LocalDate
import java.time.LocalDateTime
import java.time.LocalTime
import java.time.Month
import java.time.format.DateTimeFormatter
import java.time.format.FormatStyle
fun main(args: Array<String>) {
val datumCas = LocalDateTime.parse("2016-12-08T10:20:30")
val datum = LocalDate.parse("2016-12-08")
val cas = LocalTime.parse("10:20:30")
println(datumCas.format(DateTimeFormatter.ofLocalizedDateTime(FormatStyle.MEDIUM)))
println(datum.format(DateTimeFormatter.ofLocalizedDate(FormatStyle.MEDIUM)))
println(cas.format(DateTimeFormatter.ofLocalizedTime(FormatStyle.MEDIUM)))
}
{/KOTLIN_OOP}
Výsledek:
8.12.2016 10:20:30 8.12.2016 10:20:30
Vlastní formát
Mnohem častěji 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
{KOTLIN_OOP}
import java.time.LocalDate
import java.time.LocalDateTime
import java.time.LocalTime
import java.time.Month
import java.time.format.DateTimeFormatter
import java.time.format.FormatStyle
fun main(args: Array<String>) {
val datumCas = LocalDateTime.parse("12/08/2016 10:20:30", DateTimeFormatter.ofPattern("M/d/y HH:mm:ss"))
val datum = LocalDate.parse("12/8/2016", DateTimeFormatter.ofPattern("M/d/y"))
val cas = LocalTime.parse("10:20:30", DateTimeFormatter.ofPattern("H:m:ss"))
println(datumCas.format(DateTimeFormatter.ofLocalizedDateTime(FormatStyle.MEDIUM)))
println(datum.format(DateTimeFormatter.ofLocalizedDate(FormatStyle.MEDIUM)))
println(cas.format(DateTimeFormatter.ofLocalizedTime(FormatStyle.MEDIUM)))
}
{/KOTLIN_OOP}
Výsledek:
8.12.2016 10:20:30 8.12.2016 10:20:30
Porovnávání instancí
Nejjednodušší způsob jak porovnávat datumy (píší schválně
češtinsky nesprávně, data je v IT zavádějící slovo) je pomocí
operátorů >
, <=
, >
a
>=
. Kotlin nám pomocí metody compareTo()
přetěžuje tyto operátory. O metodě compareTo()
si ještě
povíme víc v dalších lekcích.
Pokud vám to přijde nepřehledné, můžete použít zabudované metody z
Javy, které obsahuje, protože na rozdíl od Kotlin nepodporuje
přetěžování operátorů. Tyto metody začínají 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 is*()
metod/vlastností, uveďme si i zbývající 2:
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ětChronoUnit.HOURS
, protože neobsahuje informaci o čase).
isLeapYear
je v Javě metoda, ale
Kotlin nám jí zas přegeneroval na vlastnost.
Ukažme si příklad:
{KOTLIN_OOP}
import java.time.LocalDate
import java.time.LocalDateTime
import java.time.LocalTime
import java.time.Month
import java.time.format.DateTimeFormatter
import java.time.format.FormatStyle
import java.time.temporal.ChronoUnit
fun main(args: Array<String>) {
val halloween = LocalDate.of(2016, 10, 31)
val vanoce = LocalDate.of(2016, 12, 25)
println("po: " + halloween.isAfter(vanoce))
println("před: " + halloween.isBefore(vanoce))
println("shodný: " + vanoce.isEqual(halloween))
println("shodný: " + halloween.isEqual(halloween))
println("přestupný: " + halloween.isLeapYear)
println("přestupný: " + halloween.withYear(2017).isLeapYear)
println("podporuje hodiny: " + halloween.isSupported(ChronoUnit.HOURS))
println("podporuje roky: " + halloween.isSupported(ChronoUnit.YEARS))
}
{/KOTLIN_OOP}
Výsledek:
po: false před: true shodný: false shodný: true přestupný: true přestupný: false podporuje hodiny: false podporuje roky: true
Další třídy
Kromě LocalDateTime
, LocalDate
a
LocalTime
se můžete setkat také s několika dalšími třídami,
které využijete spíše u aplikací, které jsou na práci s datem a časem
založené. Nelekejte se jich, ve většině případů si vystačíte s
LocalDateTime
, ale měli byste o nich mít povědomí.
Instant
Instant
je datum a čas, ale ne v pojetí kalendáře a
přechodů na letní čas. Je to počet nanosekund od 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:
{KOTLIN_OOP}
import java.time.LocalDate
import java.time.LocalDateTime
import java.time.LocalTime
import java.time.Month
import java.time.format.DateTimeFormatter
import java.time.format.FormatStyle
import java.time.Instant
fun main(args: Array<String>) {
val ted = Instant.now()
println(ted)
}
{/KOTLIN_OOP}
Vypíše vždy to samé. Instant
zná jen univerzální čas a
ten se bude lišit od reálného času v dané oblasti.
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 Kotlinu nalezneme také třídu OffsetDateTime
, která je
takový mezičlánek, který umožňuje zaznamenat časový posun, ale nemá
plnou podporu zón.
ZoneId
Časové zóny jsou v Kotlinu reprezentovány třídou ZoneId
.
Pojďme si udělat jednoduchou ukázku jak vytvoříme datum s časovou
zónou:
{KOTLIN_OOP}
import java.time.LocalDate
import java.time.LocalDateTime
import java.time.LocalTime
import java.time.Month
import java.time.format.DateTimeFormatter
import java.time.ZonedDateTime
import java.time.ZoneId
fun main(args: Array<String>) {
val lokalniDatumCas = ZonedDateTime.now(ZoneId.of("America/New_York"))
println(lokalniDatumCas)
}
{/KOTLIN_OOP}
Výstup:
2017-02-02T06:37:11.026-05:00[America/New_York]
Ano, je to hodně tříd, berte to spíše jako informace, ke kterým se
vrátíte, až je budete potřebovat. V Kotlinu 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 .
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 LocalDateTime
.
ofEpochSecond()
- Statická metoda nám umožňuje vytvořit datum a čas z tzv. Linux 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 od1.1.1970
(začátek linuxové epochy), musíme uvést i nanosekundy (většinou 0) a časovou zónu, což je nejčastějiZoneOffset.UTC
. Metoda je dostupná i naLocalDate
jakoofEpochDay()
, kde přijímá počet dní místo sekund.toEpochSecond()
atoEpochDay()
- 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 v Kotlinu opravdu vše.
V příští lekci, Diář s databází v Kotlin, si vytvoříme praktický příklad pro práci s
datem a časem, půjde o elektronický diář