Oktay Uğurlu
Yazılım Geliştirme Uzmanı

Java 17: Date and Time API

Java 17: Date and Time API

Date and Time API

Java 8 öncesinde kadar zaman bilgisi için Date ve Time API kullanılıyordu fakat bu API içerik olarak çok fazla detaya sahipti. Java 8 ile birlikte Date ve Time API’larında radikal değişiklikler yapıldı. Bu değişikler ile geliştiricilerin sadece 6 farklı sınıfın detaylarını bilerek tarih bilgisini geliştirdikleri uygulamalardadaha kolay bir şekilde kullanabilmeleri sağlandı. Bu sınıfları sırasıyla inceleyecek olursak:

1. LocalDate: 

  • Gün, ay, yıl bilgisini tutmak için kullanılır.
  • Artık yıl vardır:
1
2
3
4
5
System.out.println(date); // 2014-01-29

date = date.plusMonths(1);

System.out.println(date); // 2014-02-28
  • LocalDate’de dakika ve saat tutulmaz. O yüzden plusMinutes methodları yoktur.
  • LocalDate.of(2021, 1,1) şeklinde belli bir tarih için obje oluşturulabilir.

2. LocalTime: 

  • Saat, dakika, saniye, milisaniye bilgilerini tutmak için kullanılır.
  • Timezone bilgisini içermez. 
  • LocalTime.of() metodu ile minimum saat ve dakika bilgisi girerek, ekstra olarak da  saniye veya saniye + milisaniye girerek belli bir tarih için obje oluşturulabilir. of() metodunu farklı imzaları ile aşağıda görebilirsiniz:

Farklı LocalTime.of() Metodları

3. LocalDateTime: 

  • Gün, ay, yıl, saat, dakika, milisaniye bilgilerini tutmak için kullanılır.

  • Timezone bilgisini içermez. 
  • Constructor’ı private olduğu için çağırılamaz:

    LocalDateTime d = new LocalDateTime() // DOES NOT COMPILE

  • LocalDateTime.of() metodu ile birlikte minimum yıl, ay, gün, saat, dakika bilgisi girerek tercihen de saniye veya saniye + milisaniye bilgileri parametre olarak verilebilir.

  • LocalDate ve LocalTime objelerini kullanarak LocalDateTime objesi oluşturulabilir:

    LocalDateTime.of(LocalDate.now(), LocalTime.now())

4. ZonedDateTime:

  • LocalDateTime ile benzerdir, tek farkı saat dilimi bilgisini de içermesidir.
  • LocalDateTime gibi LocalDate ve LocalTime objeleri ile ZonedDateTime.of() statik metot çağırımı ile initialize edilebilir. Fakat bununla birlikte zone bilgisinin de girilmesi gerekir. Zone bilgisi girebilmek için ZoneId objesi oluşturulmalıyız:

    1
    2
    3
    4
    5
    6
    7
    8
    
    ZoneId zoneId = ZoneId.of("UTC+1"); 
    ZonedDateTime zdt = ZonedDateTime.of(2022, 10, 24, 23, 45, 59, 1234, zoneId); 
    
    //LocalDate ve LocalTime ile initialize etmek için
    LocalDate localDate = LocalDate.of(2022, 10, 24); 
    LocalTime localTime = LocalTime.of(23, 45); 
    ZoneId zoneId = ZoneId.of("GMT+03:00"); 
    ZonedDateTime timeStamp = ZonedDateTime.of( localDate, localTime, zoneId );
    

5. YearMonth

  • Yıl ve ay bilgisini tutmak için kullanılır.
  • LocalDate sınıfında da aynı isimle ve işlevle yer alan isLeapYear(), now(), plusMonths(), plusYears(), parse() gibi metodlar bu sınıfta da vardır. 
  • Bu sınıfın constructor’ı yine benzeri sınıfların constructorları gibi private olduğu için dışarıdan çağırılamaz. Obje yaratmak için diğer sınıflardaki gibi burda da of() metodu kullanılabilir. YearMonth.of(int, java.time.Month) ve YearMonth.of(int, int) şeklinde iki farklı constructor method ile initialize edilebilir.

    1
    2
    3
    4
    5
    
    YearMonth yearMonth = YearMonth.of(2022, 1);
    YearMonth yearMonth2 = YearMonth.of(2022, Month.JANUARY);
    
    System.out.println(yearMonth);  // 2022-01
    System.out.println(yearMonth2); // 2022-01
    

6. Period: 

  • Period sınıfı, LocalDate veya LocalDateTime objesine ekleme-çıkarma işlemleri yaparken belli gün ve ay bilgisi bazında eklemeyi ve çıkarmayı sağlar:

    1
    2
    3
    
    LocalDate initialDate = LocalDate.parse("2010-05-10");
    LocalDate finalDate = initialDate.plus(Period.ofDays(5));
    System.out.println(finalDate); // 2010-05-15
    
  • Aşağıdaki gibi farklı periyotlar yaratılabilir:

    1
    2
    3
    4
    5
    
    Period annually = Period.ofYears(1); // every 1 year
    Period quarterly = Period.ofMonths(3); // every 3 months
    Period everyThreeWeeks = Period.ofWeeks(3); // every 3 weeks
    Period everyOtherDay = Period.ofDays(2); // every 2 days
    Period everyYearAndAWeek = Period.of(1, 0, 7); // every year and 7 days
    
  • Period objesi oluştururken chaing call yaparak aynı anda iki farklı değer set edilemez:

    1
    2
    3
    
    Period wrong = Period.ofYears(1).ofWeeks(1); // every week
    Period wrong = Period.ofYears(1);
    wrong = Period.ofWeeks(7); // every week
    
  • Period sınıfında yalnızca hafta, yıl, ay ve gün bilgileri mevcuttur. Bu yüzden LocalTime ile kullanılamaz.

7. Duration:

  • Period gibi, LocalTime ve LocalDateTime sınıflarından oluşan objelerin tarih bilgileri için ekleme-çıkarma işlemlerinde zaman bilgisini değiştirebilmek için Duration sınıfı geliştirilmiştir.
  • ofDays(), ofHours(), ofMillis(), ofMinutes(), ofNanos(), ofSeconds() metodları ile belli zaman bilgilerini içeren Duration objeleri oluşturulabilmektedir:
  • Obje üzerinden toDays(), toHours(), toMillis(), toMinutes() metodlarını çağırarak farklı zaman bilgilerine dönüşüm yapılabilmektedir:

Önemli Detaylar:

  • Statik olarak now() metodu ile tüm sınıflardan anlık zaman bilgisini getirilebilmektedir (Period ve Duration hariç).

    1
    2
    3
    4
    
    System.out.println(LocalDate.now()); // 2022-10-13
    System.out.println(LocalDateTime.now()); // 2022-10-13T13:15:03.373812900
    System.out.println(LocalTime.now()); // 13:15:03.373812900
    System.out.println(ZonedDateTime.now()); // 2022-10-13T13:15:03.374812700+03:00[Europe/Istanbul]
    
  • Date sınıflarının hepsi Immutable’dır. Bu sınıflardan oluşan bir objenin içeriği değiştirilemez. Bundan dolayı Date ve Time API için thread safe diyebiliriz. Sınıflardaki bir metod, eğer objeyi dönüyorsa kopyasını döner:

    1
    2
    3
    4
    
    LocalDateTime localDateTime = LocalDateTime.of(2021, 1,1,0,0,0);
    LocalDateTime localDateTime1 = localDateTime.withHour(1);
    System.out.println(localDateTime1.getHour()); // 1
    System.out.println(localDateTime.getHour());  // 0
    
  • Aşağıda Date ve Time API sınflarında yer alan farklı ekleme-çıkarma işlemi yapan metodların hangi sınıflarda kullanılabildiği ve kullanılamadığı belirtilmiştir:

  LocalDateTime çağırabilir mi? LocalTime çağırabilir mi? LocalDate çağırabilir mi?
plusYears/minusYears Evet Hayır Evet
plusMonths/minusMonths Evet Hayır Evet
plusWeeks/minusWeeks Evet Hayır Evet
plusDays/minusDays Evet Hayır Evet
plusHours/minusHours Hayır Evet Evet
plusMinutes/minusMinutes Hayır Evet Evet
plusSeconds/minusSeconds Hayır Evet Evet
plusNanos/minusNanos Hayır Evet Evet

Formatting Dates and Times

  • Servisler arasında haberleşmede tarih bilgisini iletebilmek için genellikle uluslararası ortak gösterim olan ISO formatı kullanılmaktadır. Statik bir metod olan format() metodu ile tarihin yazı olarak karşılığını ISO formatında bir string değer ile döndürebiliriz:
1
2
3
4
5
6
7
LocalDate date = LocalDate.of(2020, Month.JANUARY, 20);
LocalTime time = LocalTime.of(11, 12, 34);

LocalDateTime dateTime = LocalDateTime.of(date, time);
System.out.println(date.format(DateTimeFormatter.ISO_LOCAL_DATE));          //2020-01-20
System.out.println(time.format(DateTimeFormatter.ISO_LOCAL_TIME));          //11:12:34
System.out.println(dateTime.format(DateTimeFormatter.ISO_LOCAL_DATE_TIME)); //2020-01-20T11:12:34
  • Tarih bilgisini kullanıcıya göstermek için ise aşağıdaki gibi DateTimeFormatter sınıfı kullanılarak LocalDateTime ve LocalDate objesini belli String objesine belli bir formatta dönüştürülebilir. DateTimeFormatter sınıfını oluştururken format tipini constructor metodu olan ofLocalizedDate, ofLocalizedDateTime ve ofLocalizedTime metotları ile tanımlayabilirsiniz. İsminden de anlayabileceğiniz üzere her bir metod belli Date ve Time sınıfları ile çalışabilmektedir:
1
2
3
4
5
6
7
LocalDate date =  LocalDate.of(2022,1,1);
LocalTime time = LocalTime.of(0,0);
LocalDateTime dateTime = LocalDateTime.of(date, time);

DateTimeFormatter shortDateTime = DateTimeFormatter.ofLocalizedDate(FormatStyle.SHORT);
System.out.println(shortDateTime.format(dateTime)); // 1.01.2022
System.out.println(shortDateTime.format(date)); // 1.01.2022
  • FormatStyle enum’ı sayesinde 4 farklı enum tipi ile formatlama işlemi yapılabilir:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
LocalDate date =  LocalDate.of(2022,1,1);
LocalTime time = LocalTime.of(0,0);
LocalDateTime dateTime = LocalDateTime.of(date, time);

DateTimeFormatter shortDateTime = DateTimeFormatter.ofLocalizedDate(FormatStyle.SHORT);
System.out.println(shortDateTime.format(dateTime)); // 1.01.2022

DateTimeFormatter longDateTime = DateTimeFormatter.ofLocalizedDate(FormatStyle.LONG);
System.out.println(longDateTime.format(dateTime)); // 1 Ocak 2022

DateTimeFormatter fullDateTime = DateTimeFormatter.ofLocalizedDate(FormatStyle.FULL);
System.out.println(fullDateTime.format(dateTime)); // 1 Ocak 2022 Cumartesi

DateTimeFormatter mediumDateTime = DateTimeFormatter.ofLocalizedDate(FormatStyle.MEDIUM);
System.out.println(mediumDateTime.format(dateTime)); // 1 Oca 2022
  • LocalTime objesini string formatına dönüştürmek için DateTimeFormatter.ofLocalizedTime(LocalTime) metodunun kullanılması gerekir. Fakat formatter objesini initialize ederken Zone bilgisini de setlemeniz gerekir yoksa java.time.DateTimeException hatası alınır:
1
2
3
4
5
6
7
8
LocalTime time = LocalTime.of(0,0);

DateTimeFormatter shortTime  = DateTimeFormatter.ofLocalizedTime(FormatStyle.FULL)
                .withZone(ZoneId.of("GMT+03:00"));
System.out.println(shortTime.format(time)); // 00:00:00 GMT+03:00

DateTimeFormatter shortTime  = DateTimeFormatter.ofLocalizedTime(FormatStyle.FULL);
System.out.println(shortTime.format(time)); // Exception in thread "main" java.time.DateTimeException: Unable to extract ZoneId from temporal 00:00 with chronology ISO
  • DateTimeFormatter sınıfının constructor metodlarının hangi sınıflar ile çalışabildiği aşağıda gösterilmiştir:
DateTimeFormatter f = DateTimeFormatter.___(FormatStyle.SHORT) f.format(localDate) f.format(localDateTime) f.format(localTime)
ofLocalizedDate Çalışır Çalışır Runtime hatası atar
ofLocalizedDateTime Runtime hatası atar Çalışır Runtime hatası atar
ofLocalizedTime Runtime hatası atar Çalışır Çalışır
  • Önceden tanımlanmış formatlar yerine kendi formatınızı ofPattern() metodu ile aşağıdaki gibi oluşturabilirsiniz:
1
2
3
4
5
DateTimeFormatter f = DateTimeFormatter.ofPattern("MM dd yyyy");
LocalDate date = LocalDate.parse("01 02 2015", f);
LocalTime time = LocalTime.parse("11:22");
System.out.println(date); // 2015-01-02
System.out.println(time); // 11:22
  • Kendi formatınızı oluşturabilmeniz için parametre olarak geçeceğiniz String değerin aşağıdaki kurallara uyması gerekir:
    • “MMMM” : Ay bilgisini göstermek için kullanılır. M kullanılırsa 1, MM kullanılırsa 01, MMM kullanılırsa Jan, MMMM kullanılırsa January şeklinde gösterilir.
    • ”,” : Virgül gösterilmesi için kullanılır. 
    • “dd” :Gün bilgisini göstermek için kullanılır.dd kullanılırsa 01 şeklinde gösterilir, d kullanılırsa 1 şeklinde gösterilir.
    • “yyyy” : Yıl bilgisini göstermek için kullanılır. yy ise son iki hane, yyyy 4 hane gösterilir.
    • “hh” :Saat bilgisini göstermek için kullanılır. hh kullanılırsa 01 şeklinde, h kullanılırsa 1 şeklinde gösterilir.
    • ”:”: İki nokta üst üste gösterilmesi için kullanılır
    • “mm”: Dakika bilgisinin nasıl gösterileceğini belirtmede kullanılır.

Örnek: 

1
2
3
DateTimeFormatter f = DateTimeFormatter.ofPattern("yyyy-MM-dd, HH:mm");
String formatted = f.format(LocalDateTime.now());
System.out.println(formatted); // 2022-10-13, 18:11

Referanslar: