Java 8 Tarih ve Zaman API’si: LocalDate, LocalDateTime ve Instant
Java’nın eski tarih ve zaman API’si (java.util.Date ve java.util.Calendar), geliştiricilere yıllarca hizmet vermiş olsa da, kullanım zorlukları, iş parçacığı güvenliği sorunları ve zaman dilimi yönetimi karmaşıklıkları nedeniyle sıklıkla eleştirilmiştir. Bu eksiklikleri gidermek amacıyla Java 8 ile birlikte tamamen yeni bir tarih ve zaman API’si olan java.time paketi tanıtıldı. Bu yeni API, Joda-Time projesinden esinlenerek daha okunabilir, değişmez (immutable) ve iş parçacığı açısından güvenli sınıflar sunar. Bu rehberde, Java 8’in en temel ve sık kullanılan tarih/saat sınıflarından olan LocalDate, LocalDateTime ve Instant‘ı detaylı olarak inceleyeceğiz.
Java 8 Tarih ve Zaman API’sinin Temelleri
java.time paketi, tarih ve zamanı çeşitli şekillerde temsil etmek için tasarlanmış bir dizi sınıf sunar. Bu sınıflar, farklı ihtiyaçlara yönelik olarak spesifik sorumluluklara sahiptir:
- LocalDate: Yalnızca tarihi (yıl, ay, gün) temsil eder, saat veya zaman dilimi bilgisi içermez.
- LocalTime: Yalnızca saati (saat, dakika, saniye, nanosaniye) temsil eder, tarih veya zaman dilimi bilgisi içermez.
- LocalDateTime: Tarih ve saati bir arada temsil eder, ancak zaman dilimi bilgisi içermez.
- Instant: Evrensel saat (UTC) tabanlı, epoch’tan itibaren geçen süreyi nanosaniye hassasiyetinde gösteren bir anlık zaman noktasıdır. Zaman dilimi bilgisi içermez, ancak bir zaman dilimiyle birleştirilerek anlam kazanır.
- ZonedDateTime: Bir
LocalDateTime‘a birZoneId(zaman dilimi) ekleyerek belirli bir coğrafi bölgedeki tam tarih ve zamanı temsil eder. - Duration: İki
Instant,LocalDateTimeveyaLocalTimearasındaki zaman farkını saniye ve nanosaniye cinsinden ölçer. - Period: İki
LocalDatearasındaki zaman farkını yıl, ay ve gün cinsinden ölçer.
Bu rehberde, özellikle LocalDate, LocalDateTime ve Instant üzerinde duracağız.
LocalDate: Sadece Tarih Bilgisi
LocalDate sınıfı, bir takvim tarihini (yıl, ay, gün) temsil eder. Saat veya zaman dilimi bilgisi içermez. Bu özelliği onu doğum tarihleri, tatil günleri veya bir olayın gerçekleştiği tarih gibi durumlarda ideal kılar. Değişmez (immutable) bir sınıftır, yani bir LocalDate nesnesi oluşturulduktan sonra değeri değiştirilemez; herhangi bir işlem yeni bir LocalDate nesnesi döndürür.
LocalDate Oluşturma
LocalDate nesnelerini oluşturmanın birkaç yolu vardır:
- Mevcut Tarihi Alma:
now()metodu ile sistemin varsayılan zaman dilimine göre mevcut tarihi alabilirsiniz. - Belirli Bir Tarih Oluşturma:
of()metodu ile yıl, ay ve gün değerlerini vererek belirli bir tarih oluşturabilirsiniz. - Metin Dizisinden Ayrıştırma:
parse()metodu ile ISO-8601 formatında bir metin dizisinden tarih ayrıştırabilirsiniz.
import java.time.LocalDate;
import java.time.Month;
public class LocalDateOrnekleri {
public static void main(String[] args) {
// 1. Mevcut tarihi alma
LocalDate bugun = LocalDate.now();
System.out.println("Bugünün tarihi: " + bugun); // Örn: 2023-10-26
// 2. Belirli bir tarih oluşturma
LocalDate dogumGunu = LocalDate.of(1990, 5, 15);
System.out.println("Doğum günü: " + dogumGunu); // 1990-05-15
LocalDate baskaBirGun = LocalDate.of(2024, Month.JANUARY, 1); // Month enum kullanılarak
System.out.println("Başka bir gün: " + baskaBirGun); // 2024-01-01
// 3. Metin dizisinden ayrıştırma
LocalDate tatilGunu = LocalDate.parse("2023-12-31");
System.out.println("Tatil günü: " + tatilGunu); // 2023-12-31
// Hatalı formatta ayrıştırma denemesi (DateTimeParseException fırlatır)
// LocalDate hataliTarih = LocalDate.parse("31.12.2023");
}
}
LocalDate ile İşlemler
LocalDate, tarih üzerinde çeşitli manipülasyonlar ve sorgulamalar yapmanızı sağlayan zengin bir metod setine sahiptir:
- Tarih Bileşenlerini Alma:
getYear(),getMonth(),getDayOfMonth(),getDayOfWeek()gibi metotlar. - Tarih Ekleme/Çıkarma:
plusDays(),minusMonths(),plusYears()gibi metotlar. - Tarihi Değiştirme:
withYear(),withMonth(),withDayOfMonth()gibi metotlar. - Karşılaştırma:
isBefore(),isAfter(),isEqual()metotları. - Artık Yıl Kontrolü:
isLeapYear()metodu.
import java.time.DayOfWeek;
import java.time.LocalDate;
public class LocalDateIslemleri {
public static void main(String[] args) {
LocalDate bugun = LocalDate.now();
System.out.println("Bugün: " + bugun);
// Tarih bileşenlerini alma
int yil = bugun.getYear();
Month ay = bugun.getMonth();
int gun = bugun.getDayOfMonth();
DayOfWeek haftaninGunu = bugun.getDayOfWeek();
System.out.println("Yıl: " + yil + ", Ay: " + ay + ", Gün: " + gun + ", Haftanın Günü: " + haftaninGunu);
// Tarih ekleme/çıkarma (yeni nesne döndürür)
LocalDate gelecekHafta = bugun.plusWeeks(1);
System.out.println("Gelecek hafta: " + gelecekHafta);
LocalDate gecmisAy = bugun.minusMonths(1);
System.out.println("Geçmiş ay: " + gecmisAy);
// Tarihi değiştirme (yeni nesne döndürür)
LocalDate yeniYil = bugun.withYear(2025).withMonth(1).withDayOfMonth(1);
System.out.println("Yeni Yıl (2025): " + yeniYil);
// Karşılaştırma
LocalDate yarin = bugun.plusDays(1);
System.out.println("Bugün yarından önce mi? " + bugun.isBefore(yarin)); // true
System.out.println("Bugün yarına eşit mi? " + bugun.isEqual(yarin)); // false
// Artık yıl kontrolü
LocalDate artikYil = LocalDate.of(2024, 1, 1);
System.out.println("2024 artık yıl mı? " + artikYil.isLeapYear()); // true
LocalDate normalYil = LocalDate.of(2023, 1, 1);
System.out.println("2023 artık yıl mı? " + normalYil.isLeapYear()); // false
}
}
Pratik Bilgiler: LocalDate
- Veritabanı Saklama:
LocalDategenellikle SQL’dekiDATEtipi sütunlara doğrudan eşlenebilir. JPA/Hibernate gibi ORM’ler Java 8 tarih tiplerini otomatik olarak destekler. - Doğum Tarihleri: Kişilerin doğum tarihlerini saklamak için mükemmeldir, çünkü saat veya zaman dilimi doğum gününün kendisi için genellikle önemsizdir.
- Etkinlik Tarihleri: Belirli bir günde gerçekleşecek etkinliklerin tarihlerini (konserler, resmi tatiller) yönetmek için kullanışlıdır.
LocalDateTime: Tarih ve Saat Bilgisi
LocalDateTime sınıfı, bir tarih (yıl, ay, gün) ve bir saat (saat, dakika, saniye, nanosaniye) kombinasyonunu temsil eder. Ancak, LocalDate gibi, herhangi bir zaman dilimi bilgisi içermez. Bu, onu belirli bir yerel bağlamda (örneğin, bir sunucunun yerel saati veya bir kullanıcının zaman dilimi henüz belirlenmemiş bir etkinlik saati) tarih ve saati kaydetmek için uygun kılar. Eğer zaman dilimi önemliyse, ZonedDateTime veya Instant kullanmalısınız.
LocalDateTime Oluşturma
LocalDateTime nesneleri de benzer yöntemlerle oluşturulabilir:
- Mevcut Tarih ve Saati Alma:
now()metodu ile. - Belirli Bir Tarih ve Saat Oluşturma:
of()metodu ile. - Metin Dizisinden Ayrıştırma:
parse()metodu ile ISO-8601 formatında. LocalDateveLocalTimeBirleştirme: Var olan birLocalDateveLocalTimenesnesini birleştirerek.
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
public class LocalDateTimeOrnekleri {
public static void main(String[] args) {
// 1. Mevcut tarih ve saati alma
LocalDateTime simdi = LocalDateTime.now();
System.out.println("Şimdi: " + simdi); // Örn: 2023-10-26T10:30:45.123456789
// 2. Belirli bir tarih ve saat oluşturma
LocalDateTime randevu = LocalDateTime.of(2023, 11, 15, 14, 30);
System.out.println("Randevu: " + randevu); // 2023-11-15T14:30
LocalDateTime etkinlik = LocalDateTime.of(2024, 1, 1, 9, 0, 0, 0); // Nanosaniye ile
System.out.println("Etkinlik: " + etkinlik); // 2024-01-01T09:00
// 3. Metin dizisinden ayrıştırma
LocalDateTime logZamani = LocalDateTime.parse("2023-10-26T08:00:00");
System.out.println("Log Zamanı: " + logZamani); // 2023-10-26T08:00
// 4. LocalDate ve LocalTime birleştirme
LocalDate tarih = LocalDate.of(2023, 12, 25);
LocalTime saat = LocalTime.of(18, 0);
LocalDateTime noelPartisi = LocalDateTime.of(tarih, saat);
System.out.println("Noel Partisi: " + noelPartisi); // 2023-12-25T18:00
}
}
LocalDateTime ile İşlemler
LocalDateTime de LocalDate‘a benzer manipülasyon metotlarına sahiptir, ancak hem tarih hem de saat bileşenleri üzerinde işlem yapabilir:
- Bileşenleri Alma:
getYear(),getMonth(),getHour(),getMinute()vb. - Ekleme/Çıkarma:
plusDays(),minusHours(),plusMinutes()vb. - Değiştirme:
withDayOfMonth(),withHour()vb. - Karşılaştırma:
isBefore(),isAfter(),isEqual().
import java.time.LocalDateTime;
public class LocalDateTimeIslemleri {
public static void main(String[] args) {
LocalDateTime simdi = LocalDateTime.now();
System.out.println("Şimdi: " + simdi);
// Saat bileşenlerini alma
int saat = simdi.getHour();
int dakika = simdi.getMinute();
System.out.println("Saat: " + saat + ", Dakika: " + dakika);
// Tarih ve saat ekleme/çıkarma
LocalDateTime gelecekHaftaAyniSaat = simdi.plusWeeks(1);
System.out.println("Gelecek hafta aynı saat: " + gelecekHaftaAyniSaat);
LocalDateTime besSaatSonra = simdi.plusHours(5);
System.out.println("5 saat sonra: " + besSaatSonra);
// Tarih ve saati değiştirme
LocalDateTime geceYarisi = simdi.withHour(0).withMinute(0).withSecond(0).withNano(0);
System.out.println("Bugünün gece yarısı: " + geceYarisi);
// Karşılaştırma
LocalDateTime yarinAyniSaat = simdi.plusDays(1);
System.out.println("Şimdi yarından önce mi? " + simdi.isBefore(yarinAyniSaat)); // true
}
}
Pratik Bilgiler: LocalDateTime
- Veritabanı Saklama: SQL’deki
DATETIMEveyaTIMESTAMP(zaman dilimi olmayan) sütunlara eşlenebilir. - Kullanıcı Arayüzü Gösterimi: Kullanıcının kendi yerel zaman diliminde görmesi gereken tarih ve saatler için başlangıç noktası olabilir. Ancak, global uygulamalarda bu bilgiyi
ZonedDateTime‘a dönüştürmek genellikle daha güvenlidir. - Loglama: Bir uygulamanın yerel zaman diliminde olayları kaydetmek için yaygın olarak kullanılır.
Instant: Anlık Zaman Noktası (UTC)
Instant sınıfı, zaman çizelgesinde tek, değişmez bir anlık noktayı temsil eder. Bu, “epoch” olarak bilinen 1 Ocak 1970 UTC’den bu yana geçen saniye sayısıyla ölçülür ve nanosaniye hassasiyetine kadar desteklenir. Instant, insan odaklı bir tarih ve saat bilgisi yerine, makine odaklı, evrensel (UTC) bir zaman damgasıdır. Zaman dilimi veya takvim sistemi bilgisi içermez.
Instant Oluşturma
- Mevcut Anı Alma:
now()metodu ile. - Epoch’tan Oluşturma:
ofEpochSecond()veyaofEpochMilli()metotları ile. - Metin Dizisinden Ayrıştırma:
parse()metodu ile ISO-8601 formatında (YYYY-MM-DDThh:mm:ss.nnnnnnnZ).
import java.time.Instant;
public class InstantOrnekleri {
public static void main(String[] args) {
// 1. Mevcut anı alma (UTC)
Instant simdiInstant = Instant.now();
System.out.println("Şimdi (Instant): " + simdiInstant); // Örn: 2023-10-26T07:30:45.123456789Z ('Z' UTC'yi belirtir)
// 2. Epoch'tan saniye veya milisaniye ile oluşturma
Instant epochSaniye = Instant.ofEpochSecond(0);
System.out.println("Epoch başlangıcı: " + epochSaniye); // 1970-01-01T00:00:00Z
Instant onSaniyeSonra = Instant.ofEpochSecond(10);
System.out.println("Epoch'tan 10 saniye sonra: " + onSaniyeSonra); // 1970-01-01T00:00:10Z
Instant epochMilisaniye = Instant.ofEpochMilli(1678886400000L); // 2023-03-15 00:00:00 UTC
System.out.println("Milisaniyeden oluşturulan Instant: " + epochMilisaniye); // 2023-03-15T00:00:00Z
// 3. Metin dizisinden ayrıştırma
Instant belirliAn = Instant.parse("2023-01-01T00:00:00Z");
System.out.println("Belirli bir an: " + belirliAn); // 2023-01-01T00:00:00Z
}
}
Instant ile İşlemler
Instant ile de zaman ekleme/çıkarma ve karşılaştırma işlemleri yapılabilir:
- Zaman Ekleme/Çıkarma:
plusSeconds(),minusMillis(),plus(),minus()metotları. - Karşılaştırma:
isBefore(),isAfter(),isEqual()metotları. - Dönüşümler:
toEpochMilli()metodu ile milisaniye cinsinden epoch değerini alabilirsiniz.
import java.time.Instant;
import java.time.Duration;
public class InstantIslemleri {
public static void main(String[] args) {
Instant simdi = Instant.now();
System.out.println("Şimdi (Instant): " + simdi);
// 5 dakika sonrası
Instant besDakikaSonra = simdi.plusSeconds(300); // 5 dakika = 300 saniye
System.out.println("5 dakika sonra: " + besDakikaSonra);
// 2 saat öncesi (Duration kullanarak)
Instant ikiSaatOnce = simdi.minus(Duration.ofHours(2));
System.out.println("2 saat önce: " + ikiSaatOnce);
// Karşılaştırma
System.out.println("Şimdi 5 dakika sonradan önce mi? " + simdi.isBefore(besDakikaSonra)); // true
// Epoch milisaniyesine dönüştürme (eski Date API ile uyumluluk için)
long epochMilli = simdi.toEpochMilli();
System.out.println("Epoch milisaniye: " + epochMilli);
}
}
Pratik Bilgiler: Instant
- Veritabanı Saklama: SQL’deki
TIMESTAMP WITH TIME ZONEveyaBIGINT(epoch milisaniye/saniye olarak) sütunlara eşlenebilir. En güvenli ve taşınabilir yol genellikle epoch değerini (long) saklamaktır. - Sistemler Arası İletişim: Farklı zaman dilimlerinde çalışan sistemler arasında zaman damgalarını iletmek için idealdir. Tüm sistemler aynı anlık noktayı (UTC) referans alır, bu da zaman dilimi dönüşümlerindeki hataları önler.
- Olay Sıralaması: Olayların kronolojik sırasını belirlemek için kullanılır, çünkü zaman diliminden bağımsızdır.
Zaman Dilimleri ile Çalışma: ZoneId ve ZonedDateTime
LocalDate ve LocalDateTime yerel tarih ve saatleri temsil ederken, Instant evrensel bir zaman noktasını temsil eder. Ancak gerçek dünya uygulamalarında genellikle belirli bir zaman dilimindeki tarih ve saati bilmemiz gerekir. İşte burada ZoneId ve ZonedDateTime devreye girer.
ZoneId: Bir coğrafi bölgenin zaman dilimini temsil eder (örneğin, “Europe/Istanbul”, “America/New_York”).
ZonedDateTime: Bir LocalDateTime‘a bir ZoneId ekleyerek belirli bir zaman dilimindeki tam tarih ve saati temsil eder.
Dönüşümler
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZonedDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
public class ZamanDilimiOrnekleri {
public static void main(String[] args) {
// İstanbul zaman dilimi
ZoneId istanbulZone = ZoneId.of("Europe/Istanbul");
System.out.println("İstanbul Zaman Dilimi: " + istanbulZone);
// New York zaman dilimi
ZoneId newYorkZone = ZoneId.of("America/New_York");
System.out.println("New York Zaman Dilimi: " + newYorkZone);
// 1. LocalDateTime'dan ZonedDateTime'a
LocalDateTime yerelSimdi = LocalDateTime.now();
System.out.println("Yerel şimdi (LocalDateTime): " + yerelSimdi);
ZonedDateTime istanbulSimdi = ZonedDateTime.of(yerelSimdi, istanbulZone);
System.out.println("İstanbul şimdi (ZonedDateTime): " + istanbulSimdi); // Kendi yerel saatinizi İstanbul'a göre ayarlar
// 2. Instant'tan ZonedDateTime'a
Instant evrenselSimdi = Instant.now();
System.out.println("Evrensel şimdi (Instant): " + evrenselSimdi);
ZonedDateTime istanbulAnlik = ZonedDateTime.ofInstant(evrenselSimdi, istanbulZone);
System.out.println("İstanbul anlık (ZonedDateTime): " + istanbulAnlik);
ZonedDateTime newYorkAnlik = ZonedDateTime.ofInstant(evrenselSimdi, newYorkZone);
System.out.println("New York anlık (ZonedDateTime): " + newYorkAnlik);
// Farklı zaman dilimlerinde aynı anın gösterimi
System.out.println("Aynı anın İstanbul'da görünümü: " + istanbulAnlik.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss VV")));
System.out.println("Aynı anın New York'ta görünümü: " + newYorkAnlik.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss VV")));
// ZonedDateTime'dan Instant'a geri dönüş
Instant geriDonenInstant = istanbulAnlik.toInstant();
System.out.println("Geri dönen Instant: " + geriDonenInstant); // Orijinal Instant ile aynı olmalı
}
}
Önemli Not: LocalDateTime.now(), JVM’in çalıştığı makinenin varsayılan zaman dilimini kullanır. Bu nedenle, LocalDateTime‘dan ZonedDateTime‘a dönüşüm yaparken, ZonedDateTime.of(localDateTime, zoneId) metodu, localDateTime‘ın zaten belirtilen zoneId‘da olduğu varsayılır. Eğer localDateTime‘ın başka bir zaman diliminde olduğunu ve belirtilen zoneId‘a dönüştürülmesi gerektiğini düşünüyorsanız, önce Instant‘a dönüştürüp sonra ZonedDateTime.ofInstant(instant, zoneId) kullanmak daha güvenlidir.
Formatlama ve Ayrıştırma (DateTimeFormatter)
Tarih ve zaman nesnelerini kullanıcı dostu metinlere dönüştürmek (formatlama) ve metinlerden tarih/zaman nesneleri oluşturmak (ayrıştırma) için DateTimeFormatter sınıfı kullanılır.
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.Instant;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
public class FormatlamaAyrıştırma {
public static void main(String[] args) {
LocalDate tarih = LocalDate.of(2023, 10, 26);
LocalDateTime tarihSaat = LocalDateTime.of(2023, 10, 26, 14, 35, 50);
Instant anlik = Instant.now();
ZonedDateTime zdt = ZonedDateTime.ofInstant(anlik, ZoneId.of("Europe/Istanbul"));
// 1. Önceden Tanımlanmış Formatlayıcılar
System.out.println("LocalDate (ISO_DATE): " + tarih.format(DateTimeFormatter.ISO_DATE)); // 2023-10-26
System.out.println("LocalDateTime (ISO_LOCAL_DATE_TIME): " + tarihSaat.format(DateTimeFormatter.ISO_LOCAL_DATE_TIME)); // 2023-10-26T14:35:50
System.out.println("Instant (ISO_INSTANT): " + anlik.format(DateTimeFormatter.ISO_INSTANT)); // 2023-10-26T07:35:50.123456789Z
// 2. Özel Formatlayıcılar
DateTimeFormatter ozelTarihFormat = DateTimeFormatter.ofPattern("dd.MM.yyyy EEEE");
System.out.println("Özel Tarih Formatı: " + tarih.format(ozelTarihFormat)); // 26.10.2023 Perşembe
DateTimeFormatter ozelTarihSaatFormat = DateTimeFormatter.ofPattern("yyyy/MM/dd HH:mm:ss");
System.out.println("Özel Tarih/Saat Formatı: " + tarihSaat.format(ozelTarihSaatFormat)); // 2023/10/26 14:35:50
DateTimeFormatter ozelZdtFormat = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss VV");
System.out.println("Özel ZonedDateTime Formatı: " + zdt.format(ozelZdtFormat)); // 2023-10-26 10:35:50 Europe/Istanbul
// 3. Ayrıştırma
String tarihStr = "15.08.2024";
LocalDate ayrilmisTarih = LocalDate.parse(tarihStr, DateTimeFormatter.ofPattern("dd.MM.yyyy"));
System.out.println("Ayrıştırılmış Tarih: " + ayrilmisTarih); // 2024-08-15
String tarihSaatStr = "2023-01-01 12:00:00";
LocalDateTime ayrilmisTarihSaat = LocalDateTime.parse(tarihSaatStr, DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
System.out.println("Ayrıştırılmış Tarih/Saat: " + ayrilmisTarihSaat); // 2023-01-01T12:00
}
}
Sonuç
Java 8’in java.time paketi, tarih ve zaman yönetimi için modern, temiz ve güçlü bir çözüm sunar. LocalDate, LocalDateTime ve Instant sınıfları, farklı ihtiyaçlar için özel olarak tasarlanmıştır:
LocalDate: Yalnızca tarih bilgisi gerektiren durumlar (doğum günleri, tatiller).LocalDateTime: Zaman dilimi bilgisi olmadan tarih ve saat bilgisi gerektiren durumlar (yerel olaylar, log kayıtları).Instant: Evrensel, zaman diliminden bağımsız bir anlık zaman noktası (sistemler arası iletişim, veritabanı zaman damgaları).