LocalDate, LocalTime és LocalDateTime — a java.time csomag fő osztályai, amelyek dátum és idő kezelését biztosítják időzónához való kötöttség nélkül. Az Oracle dokumentáció (Java 17, 2024) szerint ezek a típusok immutable és thread-safe ként lettek tervezve, ami biztonságossá teszi őket többszálú alkalmazások számára. Androidon API 26-tól kezdve desugaring útján váltak elérhetővé, régebbi verziókhoz pedig a ThreeTenABP könyvtáron keresztül.
Főbb pontok
LocalDate — osztály, amely a dátumot év-hónap-nap formátumban ábrázolja az idő és időzóna információi nélkül. Olyan adatok tárolására használják, mint a születési dátum, esemény dátuma vagy lejárati idő.
A LocalDate az évet -999999999 és +999999999 közötti tartományban, a hónapot 1-től 12-ig és a napot a szökőévek figyelembevételével tárolja. Az osztály teljesen immutable — minden művelet új objektumot ad vissza.
LocalTime a nap óráját reprezentálja: órák, percek, másodpercek és nanoszekundumok. Maximális pontosság — nanoszekundumig. A LocalTime nem tartalmaz információt a dátumról és az időzónáról, ami kényelmessé teszi az üzlet nyitvatartási idejének vagy egy folyamat időtartamának tárolására.
LocalDateTime egyesíti a LocalDate és LocalTime objektumokat egyetlen objektumba. Ez a leggyakrabban használt típus, amikor dátumot és időt kell tárolni, de az időzónához való kötöttség nem szükséges. Például egy koncert dátuma és ideje helyi formátumban.
Az Oracle Java Documentation (2024) szerint mindhárom osztály a Joda-Time könyvtár ötletei alapján lett tervezve, de továbbfejlesztett architektúrával és teljes integrációval a standard könyvtárba.
A java.time csomag a Java 8-ban jelent meg az elavult Date, Calendar és SimpleDateFormat osztályok helyettesítésére. Architektúrája az immutable objektumok és a fluent-interfész elveire épül.
Fő jellemző — az összes fő osztály value-based. Ez azt jelenti, hogy példányaik érték szerint összehasonlíthatók, nem referencia szerint, és nem örökíthetők. Két objektum összehasonlításához az equals metódust használjuk, nem a == operátort.
A csomag több kategóriára oszlik. Időzóna nélküli típusok — LocalDate, LocalTime, LocalDateTime — helyi dátumok és idők számára. Időzónás típusok — ZonedDateTime, OffsetDateTime, OffsetTime — eltolás vagy zóna információt adnak hozzá. Pillanatnyi típusok — Instant — egy pontot képviselnek az idővonalon UTC-ben.
Ez a felosztás megoldja a régi API-ra jellemző problémát: a programozó soha nem tudta, hogy a Date objektum tartalmaz-e időzóna információt vagy sem. A java.time-ban minden típus expliciten deklarálja a szemantikáját.
A LocalDate osztály számos metódust kínál a dátum létrehozásához, olvasásához és módosításához. Az aktuális dátum a now() statikus metóddal szerezhető meg. Egy konkrét dátum — az of(int year, int month, int dayOfMonth) metóddal.
A dátum komponenseinek olvasásához gettereket használunk: getYear(), getMonthValue(), getDayOfMonth(), getDayOfWeek(), getDayOfYear(). A getMonth() metódus a Month enumot, a getDayOfWeek() pedig a DayOfWeek enumot adja vissza.
A LocalDate támogatja a dátumok ellenőrzését. Az isBefore(), isAfter() és isEqual() metódusok lehetővé teszik a dátumok összehasonlítását. A isLeapYear() metódus ellenőrzi, hogy az év szökőév-e. A lengthOfMonth() metódus a napok számát adja vissza a hónapban, a lengthOfYear() pedig az évben.
Módosításhoz a withYear(), withMonth(), withDayOfMonth() metódusokat használjuk, amelyek a módosított komponenssel új objektumot adnak vissza. A plusDays(), minusMonths() és hasonló metódusok dátum aritmetikát végeznek.
LocalTime a nap óráját reprezentálja nanoszekundum pontossággal. Standard formátum — ISO-8601 (HH:mm:ss.nnnnnnnnn). Minimális érték — 00:00, maximális — 23:59:59.999999999.
LocalTime objektum hozható létre now() segítségével az aktuális időhöz, of(int hour, int minute), of(int hour, int minute, int second) vagy of(int hour, int minute, int second, int nanoOfSecond) segítségével. A parse(CharSequence text) metódus egy stringet dolgoz fel ISO-8601 formátumban.
A getterek közé tartozik a getHour(), getMinute(), getSecond(), getNano(). A toSecondOfDay() metódus a nap kezdetétől eltelt másodpercek számát, a toNanoOfDay() pedig a nanoszekundumokat adja vissza. Ez kényelmes az időtartam számításokhoz egy napon belül.
A LocalTime ugyanazokat az összehasonlító és módosító műveleteket támogatja, mint a LocalDate: plusHours(), minusMinutes(), withHour(), withMinute(). Az isBefore() és isAfter() metódusok figyelembe veszik az idő ciklikusságát a nap folyamán.
LocalDateTime egyesíti a LocalDate és LocalTime képességeit egyetlen osztályban. Dátumot és időt tárol, de időzóna nélkül. Ez a legrugalmasabb helyi típus, de óvatosságot igényel az elosztott rendszerekben való használatkor.
LocalDateTime létrehozható a now(), of(LocalDate date, LocalTime time), of(int year, Month month, int dayOfMonth, int hour, int minute) statikus metódusokkal és túlterheléseikkel. A LocalDate és LocalTime kombinálható az atTime() metódussal is.
A LocalDateTime hozzáférést biztosít a dátum és idő összes mezőjéhez a megfelelő gettereken keresztül: a toLocalDate() és toLocalTime() külön komponenseket ad vissza. A truncatedTo(TemporalUnit unit) metódus lehetővé teszi az idő adott pontosságra kerekítését — például percekre.
Az időzónára konvertáláshoz az atZone(ZoneId zone) metódust használjuk, amely ZonedDateTime-t ad vissza. Ez az egyetlen mód az időzóna hozzáadására a LocalDateTime-hoz.
Mindhárom osztály egységes létrehozási mintát használ statikus gyári metódusokon keresztül. Az osztályok konstruktorai private deklarálásúak — objektum nem hozható létre közvetlenül a new kulcsszóval.
Fő létrehozási módok:
Az of metódusnak számos túlterhelése van. LocalDate-hez év, hónap és nap szükséges. LocalTime-hoz — óra és perc (opcionálisan másodperc és nanoszekundum). LocalDateTime-hoz — év, hónap, nap, óra, perc. A hónapot int (1-12) vagy Month enumként lehet átadni.
val today = LocalDate.now()
val specificDate = LocalDate.of(2026, Month.JULY, 21)
val parsedDate = LocalDate.parse("2026-07-21")
val currentTime = LocalTime.now()
val lunchTime = LocalTime.of(13, 30, 0)
val parsedTime = LocalTime.parse("13:30:00")
val now = LocalDateTime.now()
val meeting = LocalDateTime.of(2026, 7, 21, 15, 0)
A java.time osztályok könnyű konverzióra lettek tervezve egymás között. LocalDate konvertálható LocalDateTime-vé az atTime(LocalTime) vagy atStartOfDay() metódussal. LocalTime — az atDate(LocalDate) segítségével.
LocalDateTime visszakonvertálható LocalDate-vé a toLocalDate() és LocalTime-vé a toLocalTime() segítségével. ZonedDateTime-vé konvertáláshoz az atZone(ZoneId) metódust használjuk.
A java.util.Date-re konvertálás (a régi kóddal való kompatibilitás érdekében) köztes lépést igényel Instant és időzóna segítségével. A Baeldung (2024) szerint ez a művelet Date.from(instant) segítségével történik.
val date = LocalDate.of(2026, 7, 21)
val dateTime = date.atTime(LocalTime.of(10, 30))
val time = LocalTime.of(14, 0)
val dateTimeFromTime = time.atDate(date)
val extractedDate = dateTime.toLocalDate()
val extractedTime = dateTime.toLocalTime()
val zoned = dateTime.atZone(ZoneId.of("Europe/Moscow"))
Formázáshoz és parsoláshoz a DateTimeFormatter osztályt használjuk. Ez előre definiált formátumokat kínál konstansek (©SO_LOCAL_DATE, ISO_LOCAL_TIME, ISO_LOCAL_DATE_TIME) és lehetőséget saját formátumok létrehozására minták segítségével.
A formázási minták szimbólumokat használnak: yyyy — év, MM — hónap (kétjegyű), dd — nap, HH — óra (0-23), mm — perc, ss — másodperc. A format() metódus a dátum-idő objektumon vagy a DateTimeFormatter segítségével hívható.
A DateTimeFormatter támogatja a lokalizációt is az ofLocalizedDate(FormatStyle), ofLocalizedTime(FormatStyle) és ofLocalizedDateTime(FormatStyle) statikus metódusokon keresztül. Elérhető stílusok: SHORT, MEDIUM, LONG és FULL.
val formatter = DateTimeFormatter.ofPattern("dd.MM.yyyy HH:mm")
val formatted = LocalDateTime.now().format(formatter)
val parsed = LocalDate.parse(
"21.07.2026",
DateTimeFormatter.ofPattern("dd.MM.yyyy")
)
Mindhárom osztály implementálja a Comparable interfészt, ami lehetővé teszi a természetes összehasonlítást. A compareTo() metódus negatív, nulla vagy pozitív számot ad vissza a sorrendtől függően. Az isBefore(), isAfter() és isEqual() metódusok boolean-t adnak vissza.
LocalDate esetén az összehasonlítás kronológiai — a korábbi dátum kisebb. LocalTime esetén — a nap órája szerint. LocalDateTime esetén — először dátum, majd idő szerint. Minden összehasonlítás helyesen veszi figyelembe a szökőéveket és a napok számát a hónapokban.
Fontos különbség a régi API-hoz képest: az equals() a LocalDate, LocalTime és LocalDateTime esetében értékeket hasonlít össze, nem referenciákat. Ez azt jelenti, hogy két azonos mezőkkel rendelkező objektum egyenlő lesz, még akkor is, ha különböző példányok.
val d1 = LocalDate.of(2026, 7, 21)
val d2 = LocalDate.of(2026, 12, 25)
if (d1.isBefore(d2)) {
Log.d("Dátum", "d1 korábban van, mint d2")
}
val sortedDates = listOf(d2, d1).sorted()
Mindhárom osztály támogatja az aritmetikai műveleteket a plus és minus metódusok segítségével. A LocalDate számára elérhető a plusDays(), plusWeeks(), plusMonths(), plusYears() és hasonló minus-metódus. A LocalTime a plusHours(), plusMinutes(), plusSeconds(), plusNanos() metódusokat támogatja.
A LocalDateTime örökli mindkét típus összes aritmetikai műveletét. A LocalDate jellemzője: hónap hozzáadásakor az eredmények helyesen kezelik a hónapok különböző hosszát. Például, január 31. + 1 hónap = február 28. (szökőévben 29.).
Bonyolultabb műveletekhez létezik a Period (dátumokhoz) és Duration (időhöz) osztály. A plus(TemporalAmount) és minus(TemporalAmount) metódusok elfogadják ezeket az objektumokat.
val today = LocalDate.now()
val nextWeek = today.plusDays(7)
val nextMonth = today.plusMonths(1)
val lastYear = today.minusYears(1)
val now = LocalTime.now()
val inTwoHours = now.plusHours(2)
val halfHourAgo = now.minusMinutes(30)
Nézzünk egy gyakorlati példát: alkalmazás munka műszakok nyilvántartására. Ki kell számítanunk a műszak időtartamát és meg kell határoznunk, hogy éjszakai időre esik-e. A LocalTime-ot használjuk a kezdő és vég időponthoz, a LocalDate-et a dátumhoz és a LocalDateTime-ot az éjfélen átnyúló műszakok számításához.
data class Shift(
val startTime: LocalTime,
val endTime: LocalTime,
val date: LocalDate
) {
fun isOvernight(): Boolean = endTime.isBefore(startTime)
fun durationInMinutes(): Long {
val start = LocalDateTime.of(date, startTime)
val end = LocalDateTime.of(
if (isOvernight()) date.plusDays(1) else date,
endTime
)
return Duration.between(start, end).toMinutes()
}
}
Második példa — a felhasználó életkorának kiszámítása. LocalDate-et használunk a születési dátumhoz és összehasonlítjuk az aktuális dátummal, figyelembe véve a születés napját és hónapját.
fun calculateAge(birthDate: LocalDate): Int {
val today = LocalDate.now()
val period = Period.between(birthDate, today)
return period.years
}
Harmadik példa — munka értesítésekkel. LocalDateTime-ot használunk emlékeztetők ütemezésére. Ellenőrizzük, hogy az ütemezett idő elérkezett-e.
data class Reminder(
val id: Long,
val scheduledAt: LocalDateTime
) {
fun isDue(): Boolean =
LocalDateTime.now().isAfter(scheduledAt)
}
A java.time beépített támogatása Androidon a API 26-tól (Android 8.0 Oreo) jelent meg. Az Android régebbi verzióival rendelkező eszközökhöz a desugaring-et kell használni — egy mechanizmust, amely az új Java API-k támogatását adja hozzá a korábbi verziókhoz.
A desugaring az Android Gradle Plugin-ben a compileOptions-on keresztül konfigurálható a build.gradle-ben. Elég az isCoreLibraryDesugaringEnabled = true beállítása és a desugar_jdk_libs könyvtár hozzáadása. Ezt követően a java.time 14-től kezdve minden API szint számára elérhető lesz.
Azokhoz a projektekhez, amelyek nem használhatják a desugaring-et (pl. 4.0 alatti AGP-n futó legacy projektek), létezik a ThreeTenABP könyvtár — a java.time backportja. Ugyanazokat az osztályokat (LocalDate, LocalTime, LocalDateTime) kínálja, de az org.threeten.bp csomagban.
@Suppress("UnstableApiUsage")
android {
compileOptions {
isCoreLibraryDesugaringEnabled = true
}
}
dependencies {
"coreLibraryDesugaring"("com.android.tools:desugar_jdk_libs:2.1.4")
}
Az első gyakori hiba — a LocalDateTime használata elosztott rendszerekben az időzóna figyelembevétele nélkül. Ha a szerver Europe/Moscow-ban van, az ügyfél pedig Asia/Tokyo-ban, a LocalDateTime eltőrően lesz értelmezve. Megoldás: globális adatokhoz használjon Instant vagy ZonedDateTime típust.
Második hiba — a stringek helytelen parsolása. Alapértelmezésben a LocalDate.parse() az ISO-8601 (yyyy-MM-dd) formátumot várja. Ha a string más formátumban van, a DateTimeFormatter-t explicit módon kell átadni. Szintén kezelni kell a DateTimeParseException-t, hogy az alkalmazás ne omoljon össze érvénytelen bemenet esetén.
Harmadik hiba — a null-biztonság figyelmen kívül hagyása. A LocalDate, LocalTime és LocalDateTime olyan objektumok, amelyek null értékűek lehetnek. Kotlinban ajánlott a nullable típusok használata explicit ellenőrzéssel vagy az Elvis operátorral. Java-ban — ellenőrizzük a null-t a metódusok meghívása előtt.
Negyedik hiba — a LocalDateTime és ZonedDateTime összetévesztése. A LocalDateTime nem tartalmaz semmilyen időzóna információt. Ha abszolút időpillanatot kell továbbítani — használjon zonális típusokat. Ha a helyi idő elegendő — lokális típusokat.
Gyakran ismételt kérdések
A Date a milliszekundumok számát tárolja 1970-01-01 UTC óta, míg a LocalDate az évet, hónapot és napot tárolja időzónához való kötöttség nélkül. A Date módosítható és nem thread-safe, a LocalDate — immutable és thread-safe. A Date elavult a Java 8 óta.
Igen, a LocalDateTime jól képezhető le az SQL TIMESTAMP WITHOUT TIME ZONE típusra. A JPA és a Room TypeConverteren keresztül támogatja. TIMESTAMP WITH TIME ZONE esetén használjon ZonedDateTime vagy OffsetDateTime típust.
Használja a ChronoUnit.DAYS.between(startDate, endDate) metódust. Ez a metódus long — a napokban mért különbséget ad vissza. Részletesebb számításhoz használja a Period.between()-t, amely évekkel, hónapokkal és napokkal tér vissza.
A LocalTime nanoszekundum pontosságot támogat (9 tizedesjegy). Ha ezredmásodperc pontosságra van szükség, használja a truncateTo(ChronoUnit.MILLIS) metódust a mentés előtt. Ez megakadályozza a kerekítési problémákat a szerializáció során.
A now() metódus az eszköz rendszeróráját és az alapértelmezett időzónát használja. Ha az eszközök különböző időzónákban vannak, a dátum eltérő lehet. Egységes időbélyeghez használja a Instant.now()-t, amely mindig az UTC időt adja vissza.
Összefoglaló
Kulcsrakész mobilalkalmazást fejlesztünk
Az IT Sectr 2017 óta készít iOS és Android alkalmazásokat induló vállalkozásoknak és vállalkozásoknak. Tanácsot adunk, és a legjobb megoldást javasoljuk.
Olvassa el is