LocalDate, LocalTime ve LocalDateTime, saat dilimine bağlı olmadan tarih ve saat işlemleri sağlayan java.time paketinin ana sınıflarıdır. Oracle belgelerine (Java 17, 2024) göre, bu türler immutable ve thread-safe olarak tasarlanmıştır, bu da onları çok iş parçacıklı uygulamalar için güvenli kılar. Android'de API 26'dan itibaren desugaring yoluyla ve daha eski sürümler için — ThreeTenABP kütüphanesi aracılığıyla kullanılabilir hale geldiler.
Önemli Noktalar
LocalDate — saat ve saat dilimi bilgisi olmadan yıl-ay-gün formatında tarihi temsil eden bir sınıf. Doğum günleri, etkinlik tarihleri veya son kullanma tarihleri gibi verileri saklamak için kullanılır.
LocalDate, -999999999 ile +999999999 aralığında yıl, 1 ile 12 arasında ay ve artık yılları dikkate alarak ayın gününü saklar. Sınıf tamamen immutable'dır — her işlem yeni bir nesne döndürür.
LocalTime günün saatini temsil eder: saat, dakika, saniye ve nanosaniye. Maksimum hassasiyet nanosaniyeye kadardır. LocalTime, tarih veya saat dilimi bilgisi içermez, bu da onu mağaza açılış saatlerini veya işlem sürelerini saklamak için kullanışlı hale getirir.
LocalDateTime LocalDate ve LocalTime'ı tek bir nesnede birleştirir. Hem tarihi hem de saati saklamanız gerektiğinde ancak saat dilimi bağlantısı gerekmediğinde en sık kullanılan türdür. Örneğin, yerel formatta bir konserin tarihi ve saati.
Oracle Java Belgelerine (2024) göre, her üç sınıf da Joda-Time kütüphanesindeki fikirlere dayanarak tasarlanmıştır, ancak geliştirilmiş mimari ve standart kütüphaneye tam entegrasyon ile.
java.time paketi, Java 8'de eski Date, Calendar ve SimpleDateFormat sınıflarının yerine geçmek üzere tanıtıldı. Mimarisi, immutable nesneler ve fluent arayüz ilkeleri üzerine inşa edilmiştir.
Önemli bir özellik — tüm ana sınıflar value-based'dır. Bu, örneklerinin referansa göre değil, değere göre karşılaştırıldığı ve miras alınamayacağı anlamına gelir. İki nesneyi karşılaştırmak için == operatörünü değil, equals yöntemini kullanın.
Paket birkaç kategoriye ayrılmıştır. Saat dilimi olmayan türler — LocalDate, LocalTime, LocalDateTime — yerel tarihler ve saatler için kullanılır. Saat dilimi olan türler — ZonedDateTime, OffsetDateTime, OffsetTime — ofset veya bölge bilgisi ekler. Anlık türler — Instant — UTC cinsinden zaman çizgisi üzerinde bir noktayı temsil eder.
Bu ayrım, eski API'de bulunan bir sorunu çözer: geliştirici, bir Date nesnesinin saat dilimi bilgisi içerip içermediğini asla bilemezdi. java.time'da her tür, anlamını açıkça bildirir.
LocalDate sınıfı, tarih oluşturma, okuma ve değiştirme için birçok yöntem sağlar. Geçerli tarih, statik yöntem now() ile alınabilir. Belirli bir tarih — of(int year, int month, int dayOfMonth) yöntemiyle alınabilir.
Tarih bileşenlerini okumak için getter'lar kullanılır: getYear(), getMonthValue(), getDayOfMonth(), getDayOfWeek(), getDayOfYear(). getMonth() yöntemi Month enum'unu, getDayOfWeek() ise DayOfWeek enum'unu döndürür.
LocalDate tarih kontrolünü destekler. isBefore(), isAfter() ve isEqual() yöntemleri tarihleri karşılaştırmaya olanak tanır. isLeapYear() yöntemi yılın artık yıl olup olmadığını kontrol eder. lengthOfMonth() yöntemi ay içindeki gün sayısını, lengthOfYear() ise yıl içindeki gün sayısını döndürür.
Değişiklik için withYear(), withMonth(), withDayOfMonth() yöntemleri kullanılır; bunlar değiştirilen bileşenle yeni bir nesne döndürür. plusDays(), minusMonths() ve benzeri yöntemler tarih aritmetiği yapar.
LocalTime nanosaniye hassasiyetinde günün saatini temsil eder. Standart biçim ISO-8601'dir (HH:mm:ss.nnnnnnnnn). Minimum değer 00:00, maksimum değer 23:59:59.999999999'dur.
Bir LocalTime nesnesi, geçerli saat için now(), of(int hour, int minute), of(int hour, int minute, int second) veya of(int hour, int minute, int second, int nanoOfSecond) ile oluşturulabilir. parse(CharSequence text) yöntemi, ISO-8601 biçimindeki bir dizeyi ayrıştırır.
Getter'lar şunları içerir: getHour(), getMinute(), getSecond(), getNano(). toSecondOfDay() yöntemi günün başlangıcından itibaren saniye sayısını döndürür ve toNanoOfDay() nanosaniyeyi döndürür. Bu, tek bir gün içindeki süreyi hesaplamak için kullanışlıdır.
LocalTime, LocalDate ile aynı karşılaştırma ve değişiklik işlemlerini destekler: plusHours(), minusMinutes(), withHour(), withMinute(). isBefore() ve isAfter() yöntemleri, zamanın bir gün içinde döngüsel olduğunu dikkate alarak çalışır.
LocalDateTime LocalDate ve LocalTime'ın yeteneklerini tek bir sınıfta birleştirir. Hem tarihi hem de saati saklar, ancak saat dilimi olmadan. Bu en esnek yerel türdür, ancak dağıtık sistemlerde kullanılırken dikkat gerektirir.
LocalDateTime, statik yöntemler now(), of(LocalDate date, LocalTime time), of(int year, Month month, int dayOfMonth, int hour, int minute) ve aşırı yüklemeleriyle oluşturulabilir. Ayrıca atTime() yöntemiyle LocalDate ve LocalTime birleştirilebilir.
LocalDateTime, ilgili getter'lar aracılığıyla tüm tarih ve zaman alanlarına erişim sağlar: toLocalDate() ve toLocalTime() bireysel bileşenleri döndürür. truncatedTo(TemporalUnit unit) yöntemi, zamanı belirli bir hassasiyete yuvarlamaya olanak tanır — örneğin, dakikalara.
Saat dilimine dönüştürmek için atZone(ZoneId zone) yöntemi kullanılır; bu, ZonedDateTime döndürür. LocalDateTime'a saat dilimi eklemenin tek yolu budur.
Her üç sınıf da statik fabrika yöntemleri aracılığıyla birleşik bir oluşturma deseni kullanır. Sınıf yapıcıları private olarak bildirilmiştir — new kullanarak doğrudan nesne oluşturulamaz.
Ana oluşturma yöntemleri:
of yönteminin birçok aşırı yüklemesi vardır. LocalDate için yıl, ay ve gün gerekir. LocalTime için — saat ve dakika (isteğe bağlı olarak saniye ve nanosaniye). LocalDateTime için — yıl, ay, gün, saat, dakika. Ay, int (1-12) veya Month enum'u olarak iletilebilir.
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)
java.time sınıfları, birbirleri arasında uygun dönüşüm için tasarlanmıştır. LocalDate, atTime(LocalTime) veya atStartOfDay() yöntemiyle LocalDateTime'a dönüştürülebilir. LocalTime — atDate(LocalDate) ile.
LocalDateTime, toLocalDate() ile LocalDate'e ve toLocalTime() ile LocalTime'a geri dönüştürülebilir. ZonedDateTime'a dönüştürmek için atZone(ZoneId) yöntemi kullanılır.
java.util.Date'e dönüşüm (eski kodla uyumluluk için), Instant ve bir saat dilimi aracılığıyla bir ara adım gerektirir. Baeldung'a (2024) göre, bu işlem Date.from(instant) aracılığıyla gerçekleştirilir.
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"))
Biçimlendirme ve ayrıştırma için DateTimeFormatter sınıfı kullanılır. Sabitler (ISO_LOCAL_DATE, ISO_LOCAL_TIME, ISO_LOCAL_DATE_TIME) aracılığıyla önceden tanımlanmış biçimler ve desen dizeleri kullanarak özel biçimler oluşturma olanağı sağlar.
Biçimlendirme desenleri semboller kullanır: yyyy — yıl, MM — ay (iki haneli), dd — gün, HH — saat (0-23), mm — dakika, ss — saniye. format() yöntemi, tarih-zaman nesnesi üzerinde veya DateTimeFormatter aracılığıyla çağrılır.
DateTimeFormatter ayrıca, ofLocalizedDate(FormatStyle), ofLocalizedTime(FormatStyle) ve ofLocalizedDateTime(FormatStyle) statik yöntemleri aracılığıyla yerelleştirmeyi de destekler. Mevcut stiller SHORT, MEDIUM, LONG ve FULL'dur.
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")
)
Her üç sınıf da Comparable arayüzünü uygulayarak doğal karşılaştırmaya olanak tanır. compareTo() yöntemi, sıraya bağlı olarak negatif, sıfır veya pozitif bir sayı döndürür. isBefore(), isAfter() ve isEqual() yöntemleri boolean döndürür.
LocalDate için karşılaştırma kronolojiktir — daha erken bir tarih daha küçük kabul edilir. LocalTime için — günün saatine göre. LocalDateTime için — önce tarihe, sonra saate göre. Tüm karşılaştırmalar artık yılları ve aylardaki gün sayısını doğru şekilde dikkate alır.
Eski API'den önemli bir fark: LocalDate, LocalTime ve LocalDateTime için equals() değerleri karşılaştırır, referansları değil. Bu, aynı alanlara sahip iki nesnenin farklı örnekler olsalar bile eşit olacağı anlamına gelir.
val d1 = LocalDate.of(2026, 7, 21)
val d2 = LocalDate.of(2026, 12, 25)
if (d1.isBefore(d2)) {
Log.d("Tarih", "d1, d2'den önce")
}
val sortedDates = listOf(d2, d1).sorted()
Her üç sınıf da plus ve minus yöntemleri aracılığıyla aritmetik işlemleri destekler. LocalDate için plusDays(), plusWeeks(), plusMonths(), plusYears() ve karşılık gelen minus yöntemleri mevcuttur. LocalTime, plusHours(), plusMinutes(), plusSeconds(), plusNanos()'u destekler.
LocalDateTime, her iki türden tüm aritmetik işlemleri devralır. LocalDate'in dikkate değer bir özelliği: bir ay eklendiğinde, sonuçlar farklı ay uzunluklarını doğru şekilde işler. Örneğin, 31 Ocak + 1 ay = 28 (artık yılda 29) Şubat.
Daha karmaşık işlemler için Period sınıfı (tarihler için) ve Duration sınıfı (zaman için) bulunur. plus(TemporalAmount) ve minus(TemporalAmount) yöntemleri bu nesneleri kabul eder.
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)
Pratik bir örneğe bakalım: iş vardiyası takip uygulaması. Vardiya süresini hesaplamamız ve gece saatine denk gelip gelmediğini belirlememiz gerekiyor. Başlangıç ve bitiş saatleri için LocalTime, tarih için LocalDate ve gece yarısını geçen vardiyaları hesaplamak için LocalDateTime kullanıyoruz.
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()
}
}
İkinci bir örnek — kullanıcının yaşını hesaplama. Doğum tarihi için LocalDate kullanıyoruz ve doğum günü ve ayını dikkate alarak geçerli tarihle karşılaştırıyoruz.
fun calculateAge(birthDate: LocalDate): Int {
val today = LocalDate.now()
val period = Period.between(birthDate, today)
return period.years
}
Üçüncü bir örnek — bildirimlerle çalışma. LocalDateTime hatırlatıcıları planlamak için kullanılır. Planlanan zamanın gelip gelmediğini kontrol ederiz.
data class Reminder(
val id: Long,
val scheduledAt: LocalDateTime
) {
fun isDue(): Boolean =
LocalDateTime.now().isAfter(scheduledAt)
}
java.time için yerleşik destek, Android'de API 26'dan (Android 8.0 Oreo) itibaren ortaya çıktı. Daha eski Android sürümlerine sahip cihazlar için, desugaring — yeni Java API'lerinin desteğini önceki sürümlere ekleyen bir mekanizma — kullanılması gerekir.
Android Gradle Plugin'de Desugaring, build.gradle'daki compileOptions aracılığıyla yapılandırılır. Sadece isCoreLibraryDesugaringEnabled = true olarak ayarlayın ve desugar_jdk_libs kütüphanesini ekleyin. Bundan sonra java.time, 14'ten itibaren tüm API seviyelerinde kullanılabilir hale gelir.
Desugaring kullanamayan projeler için (örneğin, AGP 4.0'ın altındaki eski projeler), ThreeTenABP kütüphanesi bulunur — java.time'ın bir geri uyumluluk sürümü. Aynı sınıfları (LocalDate, LocalTime, LocalDateTime) sağlar, ancak org.threeten.bp paketinde.
@Suppress("UnstableApiUsage")
android {
compileOptions {
isCoreLibraryDesugaringEnabled = true
}
}
dependencies {
"coreLibraryDesugaring"("com.android.tools:desugar_jdk_libs:2.1.4")
}
İlk yaygın hata — saat dilimlerini dikkate almadan dağıtık sistemlerde LocalDateTime kullanmak. Sunucu Europe/Moscow'da ve istemci Asia/Tokyo'da ise, LocalDateTime farklı yorumlanacaktır. Çözüm: genel veriler için Instant veya ZonedDateTime kullanın.
İkinci hata — yanlış dize ayrıştırma. Varsayılan olarak, LocalDate.parse() ISO-8601 biçimini (yyyy-MM-dd) bekler. Dize başka bir biçimdeyse, açıkça bir DateTimeFormatter iletmeniz gerekir. Ayrıca geçersiz girişte uygulamanın çökmemesi için DateTimeParseException'ı işlemelisiniz.
Üçüncü hata — null güvenliğini göz ardı etmek. LocalDate, LocalTime ve LocalDateTime null olabilen nesnelerdir. Kotlin'de açık kontroller veya Elvis operatörüyle nullable türler kullanılması önerilir. Java'da — yöntemleri çağırmadan önce null'u kontrol edin.
Dördüncü hata — LocalDateTime ve ZonedDateTime'ı karıştırmak. LocalDateTime saat dilimi bilgisi içermez. Zamanda mutlak bir anı iletmeniz gerekiyorsa — bölgesel türler kullanın. Yerel saat yeterliyse — yerel türleri kullanın.
Sıkça Sorulan Sorular
Date, 1970-01-01 UTC'den itibaren milisaniye sayısını saklarken, LocalDate saat dilimi bağlantısı olmadan yıl, ay ve günü saklar. Date değişebilir ve thread-safe değildir, LocalDate immutable ve thread-safe'dir. Date, Java 8'den beri kullanımdan kaldırılmıştır.
Evet, LocalDateTime SQL türü TIMESTAMP WITHOUT TIME ZONE'a iyi şekilde eşlenir. JPA ve Room, TypeConverter aracılığıyla destekler. TIMESTAMP WITH TIME ZONE için ZonedDateTime veya OffsetDateTime kullanın.
ChronoUnit.DAYS.between(startDate, endDate) kullanın. Bu yöntem long döndürür — gün cinsinden fark. Daha ayrıntılı hesaplama için, yıllar, aylar ve günlerle Period döndüren Period.between()'i kullanın.
LocalTime nanosaniye hassasiyetini (9 ondalık basamak) destekler. Milisaniye hassasiyeti yeterliyse, kaydetmeden önce truncateTo(ChronoUnit.MILLIS) kullanın. Bu, serileştirme sırasında yuvarlama sorunlarını önler.
now() yöntemi, cihazın sistem saatini ve varsayılan saat dilimini kullanır. Cihazlar farklı saat dilimlerindeyse, tarih farklı olabilir. Birleşik bir zaman damgası için her zaman UTC saatini döndüren Instant.now()'u kullanın.
Özet
Anahtar teslim bir mobil uygulama geliştireceğiz
IT Sectr, 2017'den beri girişimler ve işletmeler için iOS ve Android uygulamaları oluşturmaktadır. Size danışmanlık yapacak ve en iyi çözümü önereceğiz.
Ayrıca okuyun