Eğitim Portalı/Java/Date & Time (java.time)
Java01-java/88-tarih-ve-zaman

Date & Time (java.time)

Tarih ve saatle çalışmak, neredeyse her uygulamada gereklidir: kayıt zamanı, doğum tarihi, randevu, zaman damgası, geri sayım. Java 8'e kadar bu, hatalı ve sinir bozucu Date/Calendar sınıflarıyla yapılırdı. Java 8, ja…

Date & Time (java.time)

Tarih ve saatle çalışmak, neredeyse her uygulamada gereklidir: kayıt zamanı, doğum tarihi, randevu, zaman damgası, geri sayım. Java 8'e kadar bu, hatalı ve sinir bozucu Date/Calendar sınıflarıyla yapılırdı. Java 8, java.time paketini getirdi: değişmez, açık ve doğru tasarlanmış modern bir tarih/saat API'si. Bu konu, tarih/saatle güvenle çalışmayı baştan sona ele alır.

Neden eski Date/Calendar değil?

Eski API'nin sorunları efsanevidir: Date değişebilir (mutable — thread-safe değil), aylar 0'dan başlar (Ocak = 0!), yıl 1900'den sayılır, SimpleDateFormat thread-safe değildir. java.time bunların hepsini çözer: değişmez, açık adlandırma, mantıklı değerler.

Temel tipler

TipNe tutarÖrnek
LocalDateYalnızca tarih2026-06-23
LocalTimeYalnızca saat14:30
LocalDateTimeTarih + saat (bölgesiz)2026-06-23T14:30
ZonedDateTimeTarih + saat + bölge...Europe/Istanbul
InstantZaman çizgisinde bir an (UTC)epoch tabanlı
PeriodTarih farkı (yıl/ay/gün)30 yıl 1 ay
DurationZaman farkı (saat/dk/sn)8 saat 30 dk

Oluşturma ve aritmetik

LocalDate t = LocalDate.of(2026, Month.JUNE, 23);   // sabit
LocalDate bugun = LocalDate.now();                   // şu an
t.plusDays(10); t.minusMonths(2); t.plusYears(1);    // YENİ nesne (immutable!)
t.getDayOfWeek();                                    // gün adı
dun.isBefore(t); t.isAfter(dun);                     // karşılaştırma

Değişmezlik: Tüm java.time tipleri değişmezdir; plus/minus orijinali değiştirmez, yeni bir nesne döndürür. t.plusDays(10); tek başına bir işe yaramaz — sonucu kullanmalısın.

Örnek 1 (./Ornek1.java) temel tipleri, aritmetiği, Period/Duration ve ChronoUnit.between ile fark hesabını gösterir.

Biçimlendirme ve ayrıştırma

DateTimeFormatter, tarih/saat ↔ String dönüşümünü yapar:

DateTimeFormatter f = DateTimeFormatter.ofPattern("dd.MM.yyyy HH:mm");
dt.format(f);                          // tarih -> "23.06.2026 14:30"
LocalDateTime.parse("15.08.2026 09:45", f);  // String -> tarih

Desen harfleri: yyyy yıl, MM ay (sayı), MMMM ay (ad), dd gün, HH saat (24'lük), mm dakika, EEEE gün adı. Locale ile dile özgü (Türkçe ay/gün adları) biçim alınır. Örnek 2 (./Ornek2.java) biçimlendirme ve ayrıştırmayı gösterir.

Thread-safety: Eski SimpleDateFormat'ın aksine, DateTimeFormatter thread-safe'dir; bir kez oluşturup paylaşabilirsin.

Zaman dilimleri ve Instant

Küresel uygulamalarda zaman dilimi kritiktir:

ZonedDateTime ist = ZonedDateTime.of(dt, ZoneId.of("Europe/Istanbul"));
ZonedDateTime ny = ist.withZoneSameInstant(ZoneId.of("America/New_York")); // aynı an, farklı yerel saat
Instant an = ist.toInstant();          // mutlak an (UTC, epoch)
  • ZonedDateTime: Belirli bir bölgedeki tarih/saat (yaz saati dahil).
  • Instant: Zaman çizgisindeki mutlak bir an (UTC, epoch'tan beri). Loglar, zaman damgaları, makineler arası iletişim için.

Örnek 2 İstanbul ↔ New York dönüşümünü ve Instant'ı gösterir.

Altın kural: Zamanı UTC olarak sakla/ilet (Instant), yalnızca kullanıcıya gösterirken yerel bölgeye çevir. Bu, zaman dilimi ve yaz saati hatalarını önler.

Spring/JPA ile

Modern Java/Spring java.time tiplerini doğrudan destekler: JPA @Entity alanları LocalDate/ LocalDateTime/Instant olabilir; Jackson bunları JSON'a (ISO-8601) çevirir; veritabanı sürücüleri eşler. Yani eski Date'e dönmene gerek yoktur.

Özet

Modern java.time API'sini öğrendik: neden eski Date/Calendar'dan üstün olduğunu; temel tipleri (LocalDate/Time/DateTime), değişmez aritmetiği, Period/Duration (Örnek 1); biçimlendirme/ ayrıştırmayı (DateTimeFormatter) ve zaman dilimlerini (ZonedDateTime/Instant; Örnek 2) gördük; "UTC sakla, yerelde göster" kuralını ve Spring/JPA entegrasyonunu ele aldık. Bununla temel/kavramsal derin konular batch'i tamamlandı.

Kod Örnekleri(2)

Ornek1

çalıştırılabilir
Ornek1.java
1// Ornek1: java.time temelleri — LocalDate, LocalTime, LocalDateTime, Period, Duration.
2// Çalıştırma: java Ornek1.java
3import java.time.Duration;
4import java.time.LocalDate;
5import java.time.LocalDateTime;
6import java.time.LocalTime;
7import java.time.Month;
8import java.time.Period;
9import java.time.temporal.ChronoUnit;
10
11public class Ornek1 {
12
13    public static void main(String[] args) {
14        // LocalDate: yalnızca tarih (saat yok). of(...) ile sabit, now() ile bugün.
15        LocalDate tarih = LocalDate.of(2026, Month.JUNE, 23);
16        System.out.println("Tarih: " + tarih + " | gün: " + tarih.getDayOfWeek());
17
18        // Aritmetik: DEĞİŞMEZ (immutable) -> her işlem YENİ nesne döndürür.
19        System.out.println("10 gün sonra : " + tarih.plusDays(10));
20        System.out.println("2 ay önce    : " + tarih.minusMonths(2));
21        System.out.println("Gelecek yıl  : " + tarih.plusYears(1));
22
23        // LocalTime ve LocalDateTime
24        LocalTime saat = LocalTime.of(14, 30, 0);
25        LocalDateTime tam = LocalDateTime.of(tarih, saat);
26        System.out.println("\nSaat: " + saat + " | Tam: " + tam);
27
28        // Karşılaştırma
29        LocalDate dun = tarih.minusDays(1);
30        System.out.println("\ndün, bugünden önce mi? " + dun.isBefore(tarih));
31
32        // Period: TARİH farkı (yıl/ay/gün). Duration: ZAMAN farkı (saat/dakika/saniye).
33        LocalDate dogum = LocalDate.of(1995, 5, 20);
34        Period yas = Period.between(dogum, tarih);
35        System.out.println("\nYaş: " + yas.getYears() + " yıl " + yas.getMonths() + " ay " + yas.getDays() + " gün");
36        System.out.println("Toplam gün (ChronoUnit): " + ChronoUnit.DAYS.between(dogum, tarih));
37
38        Duration sure = Duration.between(LocalTime.of(9, 0), LocalTime.of(17, 30));
39        System.out.println("Mesai süresi: " + sure.toHours() + " saat " + (sure.toMinutes() % 60) + " dk");
40
41        System.out.println("""
42
43                --- java.time temelleri (Java 8+) ---
44                LocalDate (tarih), LocalTime (saat), LocalDateTime (ikisi) — hepsi DEĞİŞMEZ ve thread-safe.
45                of(...) sabit oluşturur; now() şu anı verir; plus/minus YENİ nesne döndürür (orijinali değişmez).
46                Period: tarih farkı (yıl/ay/gün). Duration: zaman farkı (saat/dk/sn). ChronoUnit.between: tek birimde fark.
47                Eski Date/Calendar'a göre: değişmez, açık, hatasız. (Date değişebilir ve thread-safe değildi.)""");
48    }
49}
Çıktı yerel JDK 21 ile yakalandı — tarayıcıda JVM çalışmaz.

Ornek2

çalıştırılabilir
Ornek2.java
1// Ornek2: Biçimlendirme/ayrıştırma (DateTimeFormatter) ve zaman dilimleri (ZonedDateTime, Instant).
2// Çalıştırma: java Ornek2.java
3import java.time.Instant;
4import java.time.LocalDateTime;
5import java.time.ZoneId;
6import java.time.ZonedDateTime;
7import java.time.format.DateTimeFormatter;
8import java.util.Locale;
9
10public class Ornek2 {
11
12    public static void main(String[] args) {
13        LocalDateTime dt = LocalDateTime.of(2026, 6, 23, 14, 30, 0);
14
15        // BİÇİMLENDİRME: tarih/saat -> okunabilir String (DateTimeFormatter).
16        DateTimeFormatter trFormat = DateTimeFormatter.ofPattern("dd.MM.yyyy HH:mm");
17        System.out.println("Biçimli (tr): " + dt.format(trFormat));
18        DateTimeFormatter uzun = DateTimeFormatter.ofPattern("d MMMM yyyy, EEEE", new Locale("tr"));
19        System.out.println("Uzun (tr)   : " + dt.format(uzun));
20        System.out.println("ISO standart: " + dt.format(DateTimeFormatter.ISO_DATE_TIME));
21
22        // AYRIŞTIRMA: String -> tarih/saat (parse). Format eşleşmeli.
23        LocalDateTime ayristirilan = LocalDateTime.parse("15.08.2026 09:45", trFormat);
24        System.out.println("\nAyrıştırılan: " + ayristirilan);
25
26        // ZAMAN DİLİMLERİ: ZonedDateTime belirli bir bölgedeki zamanı temsil eder.
27        ZonedDateTime istanbul = ZonedDateTime.of(dt, ZoneId.of("Europe/Istanbul"));
28        ZonedDateTime newYork = istanbul.withZoneSameInstant(ZoneId.of("America/New_York"));
29        System.out.println("\nİstanbul: " + istanbul.format(trFormat) + " " + istanbul.getZone());
30        System.out.println("New York: " + newYork.format(trFormat) + " " + newYork.getZone()
31                + "  (AYNI an, farklı yerel saat)");
32
33        // Instant: zaman çizgisindeki bir an (UTC, epoch'tan beri). Makineler/zaman damgaları için.
34        Instant an = istanbul.toInstant();
35        System.out.println("\nInstant (UTC): " + an);
36        System.out.println("Epoch saniye : " + an.getEpochSecond());
37
38        System.out.println("""
39
40                --- Biçimlendirme, ayrıştırma ve zaman dilimleri ---
41                DateTimeFormatter: ofPattern(\"dd.MM.yyyy HH:mm\") ile biçimlendir (format) ve ayrıştır (parse).
42                  Desen harfleri: yyyy yıl, MM ay(sayı), MMMM ay(ad), dd gün, HH saat(24), mm dk, EEEE gün adı.
43                ZonedDateTime: belirli bir BÖLGEDEKİ tarih/saat (ZoneId). withZoneSameInstant: aynı anı başka bölgede göster.
44                Instant: zaman çizgisindeki mutlak bir an (UTC, epoch tabanlı) — zaman damgaları/loglar için.
45                Kural: depolama/iletişimde UTC (Instant) sakla; KULLANICIYA gösterirken yerel bölgeye çevir.""");
46    }
47}
Çıktı yerel JDK 21 ile yakalandı — tarayıcıda JVM çalışmaz.