Koray PEKER
Menu
  • Anasayfa
  • Kütüphane
  • Kategoriler
    • Java
    • Spring
    • Tasarım Şablonları
    • Git
    • Maven
    • ORM Çatıları
    • VCS
    • SDLC
    • DevOps
    • Algoritma
    • Eğitim
    • Diğer
  • Hakkımda
Menu

Java 8 : Date/Time API

9 Aralık 20182 Ocak 2019 tarihinde yayımlandı

JDK 1.0 ile beraber Date sınıfı java’ya kazandırılmıştı. Date sınıfında görülen eksiklikler sonrasında, bu eksikleri kapatmak için bir sonraki sürümde yani JDK 1.1 ile Calendar sınıfı geldi. Fakat bu tasarımların kusurları ve tutarsızlıkları nedeniyle, kurumsal uygulamaların çoğu JodaTime gibi third-party çözümleri kullanmak zorunda kalmıştır. Java’nın sürümleri ile ilgili detaylı yazıyı okumak için tıklayınız.

Java 8 ile beraber, eski tarih-zaman API’sinin (java.util.Date ve java.util.Calendar) dezavantajlarını karşılamak için yeni bir tarih-zaman API’si tanıtıldı. Bu yeni API, java.time paketi altında bulunur. Eğer JodaTime ile çalıştıysanız, öğrenmeniz gerçekten kolay olacaktır. Aslına bakarsanız, JodaTime’ı hiç duymamış insanların bile öğrenmesi kolay olacaktır; çünkü basit düşünülerek tasarlanmıştır.

Önce aşağıdaki kodlara bakıp geçmişi hatırlayalım ve sonra dezavantajlardan bahsedelim.

Java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
Date today = new Date();
System.out.println(today);
// Wed Dec 05 21:42:48 EET 2018
// Varsayılan zaman dilimi içeriyor.
 
Date elevenApril2018Date = new Date(118, 3, 11);
System.out.println(elevenApril2018Date);
// Wed Apr 11 00:00:00 EET 2018
// Ay 0'dan başlıyor ve yıl 1900'den başlıyor. zaman dilimi içeriyor.
 
Calendar elevenApril2018Calendar = new GregorianCalendar(2018,3,11);
System.out.println(elevenApril2018Calendar.getTime());
// Wed Apr 11 00:00:00 EET 2018
// Ay 0'dan başlıyor fakat yılı düzeltilmiş. zaman dilimi içeriyor.
 
DateFormat ddMMyyySDF = new SimpleDateFormat("dd/MM/yyyy");
System.out.println(ddMMyyySDF.format(elevenApril2018Date));
// 11/04/2018
// zaman dilim içermemesi için formatlamak gerekiyor Fakat DateFormat thread-safe değildir.

  • Immutable ve Thread Safe – java.util.Date ve java.util.Calendar API’leri thread-safe değildir ve olası eşzamanlılık sorunlarına yol açmaktadır. (Immutable ile  ilgili detaylı  bilgiyi buradan okuyabilirsiniz.) Java 8’deki Tarih ve Zaman API’leri immutable‘dir ve bu nedenle thread-safe’dir.
  • Uygun API tasarımı ve çeşitli yardımcı metotlar – java.util.Date ve java.util.Calendar API’leri yardımcı metotlar açısından epeyce eksiktir. Bu sebeplerden dolayı java 8 olmayan projelerimizde ayrıyeten bir DateUtil API’si yazılmıştır. Yeni Tarih / Zaman API’sı ISO-8601 merkezlidir ve çeşitli faydalı yöntemlere sahiptir.
  • Zaman Dilimi – Daha önce java.util.Date ve java.util.Calendar API’leri ile farklı zaman dilimi (timezone) kullanmak çok zordu. Ayrıca zaman dilimlerine sıkı sıkı bağımlıydı. Java 8 ile beraber zaman dilimleri bağımsız oldular. İhtiyaç doğrultusunda rahatlıkla kullanabilirsiniz.
  • Okunabilirlik – Java 8 tarih-zaman API’sinden önce, Java tarafından sağlanan yöntemlerin çoğunun okunabilirliği yoktu ve kullanımdan önce kodun altında yatan çalışma hakkında bilgiye ihtiyaç vardı.
  • Kötü Tasarım – Date sınıfı tarih değil, timestamp’dir. Calendar ise tarih ve zamanın karışımıdır. Ayrıca yıl1900’den başlar, ay 1’den başlar ve gün 0’dan başlar.

ISO-8601 Standardı

ISO-8601, standart bir tarih ve saat sunma yöntemini kullanmak isteyen herkes tarafından kullanılabilir. Uluslararası iletişim kurarken belirsizlik ve karışıklığı ortadan kaldırmaya yardımcı olur. Detaylı bilgi için tıklayınız. Java da artık bu standardı kullanmaya başladı.

Java 8 : Date/Time API

LocalDate, LocalTime, LocalDateTime, Period ve Duration gibi yaygın olarak kullanılan tüm sınıflar java.time paketinin bir parçasıdır.

LocalDate

LocalDate sınıfı, ISO-8601 standardını kullanan ve zaman dilimi olmayan tarih sınıfıdır. Örneğin ; 2018-12-03.

Java
1
2
3
4
5
6
7
8
9
10
11
LocalDate localDate1 = LocalDate.of(2018, 4, 11);
LocalDate localDate2 = LocalDate.parse("2018-02-13");
LocalDate localDate3 = LocalDate.now();
LocalDate localDate4 = LocalDate.ofYearDay(2015, 100);
 
System.out.println(localDate1.toString());                //2018-04-11
System.out.println(localDate1.getDayOfWeek().toString()); //WEDNESDAY
System.out.println(localDate1.getDayOfMonth());           //11
System.out.println(localDate1.getDayOfYear());            //101
System.out.println(localDate1.isLeapYear());              //false
System.out.println(localDate1.plusDays(12).toString());   //2018-04-23

LocalTime

LocalTime sınıfı, ISO-8601 standardını kullanan ve zaman dilimi olmayan zaman sınıfıdır.

Örneğin ; 10:15:30.

Java
1
2
3
4
5
6
7
8
9
10
11
12
13
LocalTime localTime1 = LocalTime.of(15, 30, 28);
LocalTime localTime2 = LocalTime.now();     //toString() in format 09:57:59.744
LocalTime localTime3 = LocalTime.of(12, 20);
LocalTime localTime4 = LocalTime.ofSecondOfDay(10160);
LocalTime localTime5 = LocalTime.parse("06:30");
 
System.out.println(localTime1);               // 15:30:28
System.out.println(localTime1.getHour());     // 15
System.out.println(localTime1.getMinute());   // 30
System.out.println(localTime1.getSecond());   // 28
System.out.println(localTime1.MIDNIGHT);      // 00:00
System.out.println(localTime1.NOON);          // 12:00
System.out.println("seconds of the day: " + localTime4); // seconds of the day: 02:49:20

LocalDateTime

LocalDateTime sınıfı, ISO-8601 standardını kullanan ve zaman dilimi olmayan tarih-zaman sınıfıdır. Örneğin ; 2018-05-15T10:01:14.911

Java
1
2
3
4
5
6
7
8
9
LocalDateTime localDateTime1 = LocalDateTime.now();
LocalDateTime localDateTime2 = LocalDateTime.of(1987, Month.APRIL, 11, 14, 0, 0);
LocalDateTime localDateTime3 = LocalDateTime.parse("2018-02-13T06:30");
LocalDateTime localDateTime4 = LocalDate.parse("2018-02-13").atTime(LocalTime.parse("06:30"));
LocalDateTime localDateTime5 = LocalTime.parse("06:30").atDate(LocalDate.parse("2018-02-13"));
 
LocalTime timeNow = LocalTime.now();
LocalDate dateToday = LocalDate.now();
LocalDateTime localDateTime6 = LocalDateTime.of(dateToday, timeNow);

Zoned Date-Time API

Java 8 de, zaman dilimini belirli bir tarih ve saatle başa çıkmak için ZonedDateTime sınıfı vardır. ZoneId, farklı bölgeleri temsil etmek için kullanılan bir tanımlayıcıdır.

Java
1
2
3
4
5
ZoneId currentZone = ZoneId.systemDefault(); // Asia/Istanbul
ZoneId id = ZoneId.of("Asia/Istanbul");
ZonedDateTime zonedDateTime = ZonedDateTime.parse("2018-12-03T10:15:30+05:30[Asia/Istanbul]");
ZonedDateTime zonedDateTime1 = ZonedDateTime.now(); // 2018-12-08T10:20:45.063+03:00[Asia/Istanbul]
Set<String> allZoneIds = ZoneId.getAvailableZoneIds();

Chrono Units Enum

Zaman birimlerini göstermek için java.time.temporal.ChronoUnit enum’u geldi. Bu enum içerisinde 100 yıl , 10 yıl , 1 yıl , 1 hafta gibi zaman birimleri bulunmaktadır.

Java
1
2
3
4
5
6
7
8
9
10
11
12
13
LocalDate today = LocalDate.now();
 
LocalDate nextWeek = today.plus(1, ChronoUnit.WEEKS);
System.out.println("1 hafta sonra : " + nextWeek);
 
LocalDate nextMonth = today.plus(1, ChronoUnit.MONTHS);
System.out.println("1 ay sonra : " + nextMonth);
 
LocalDate nextYear = today.plus(1, ChronoUnit.YEARS);
System.out.println("1 yıl sonra : " + nextYear);
 
LocalDate nextDecade = today.plus(1, ChronoUnit.DECADES);
System.out.println("10 yıl sonra : " + nextDecade);

Period and Duration

Java 8 ile, iki tarih ve iki zaman arasındaki farkları hesaplamak için iki özel sınıf tanıtıldı.

  • Period – Tarih bazlı aralık ile ilgilenir.
  • Duration – Zaman bazlı aralık ile ilgilenir.

Java
1
2
3
4
5
6
7
LocalDate currTime = LocalDate.now();
LocalDate dateAfter10Days = currTime.plus(Period.ofDays(10));
LocalDate dateBeforeWeek = currTime.minus(Period.ofWeeks(3));
 
Period periofDiff = Period.between(dateBeforeWeek, dateAfter10Days); //P1M1D
System.out.println("day difference: " + periofDiff.getDays());
System.out.println("months difference: " + periofDiff.getMonths());

Java
1
2
3
4
5
6
LocalTime givenTime = LocalTime.of(2, 30, 15); // 02:30:15
LocalTime updatedTime = givenTime.plus(Duration.ofMinutes(20)).plus(Duration.ofSeconds(30)); // 02:50:45
 
Duration drt = Duration.between(givenTime, updatedTime); // PT20M30S
System.out.println("İki saat arasındaki saniye farkı : " + drt.getSeconds()); // 1230
System.out.println("iki saat arasındaki dakika farkı : " + drt.toMinutes()); // 20

Temporal Adjusters

TemporalAdjuster, tarih matematiğini yapmak için kullanılır. Örneğin, “Ayın İkinci Cumartesi” veya “Gelecek Salı” olsun. Hadi bir örnek yapalım.

Java
1
2
3
4
5
6
7
8
9
LocalDate localDate = LocalDate.now();
 
// Bir sonraki ilk cumartesi
LocalDate nextTuesday = localDate.with(TemporalAdjusters.next(DayOfWeek.TUESDAY));
 
//Ayın ikinci cumartesisi
LocalDate firstInYear = LocalDate.of(localDate.getYear(),localDate.getMonth(), 1);
LocalDate secondSaturday = firstInYear.with(TemporalAdjusters.nextOrSame(DayOfWeek.SATURDAY))
        .with(TemporalAdjusters.next(DayOfWeek.SATURDAY));

Backward Compatibility (Geriye dönük uyumluluk)

Yeni Date-Time API’sine dönüştürmek için Date and Calendar sınıflarına toInstant() yöntemi eklendi. LocalDateTime veya ZonedDateTime nesnesi almak için ofInstant (Insant, ZoneId) yöntemini kullanabilirsiniz.

Java
1
2
3
4
5
6
7
8
9
10
11
12
13
//Get the current date
Date currentDate = new Date();
System.out.println("Current date: " + currentDate);
 
//Get the instant of current date in terms of milliseconds
Instant now = currentDate.toInstant();
ZoneId currentZone = ZoneId.systemDefault();
 
LocalDateTime localDateTime = LocalDateTime.ofInstant(now, currentZone);
System.out.println("Local date: " + localDateTime);
 
ZonedDateTime zonedDateTime = ZonedDateTime.ofInstant(now, currentZone);
System.out.println("Zoned date: " + zonedDateTime);

DateTimeFormatter

İstenilen deseni kullanarak belirli bir tarihi ayrıştırmak mümkündür.

Java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
LocalDate fromString = LocalDate.parse( "2014-01-20" );
LocalDate parsedFromPatern = LocalDate.parse( "2014/03/03", DateTimeFormatter.ofPattern( "yyyy/MM/dd" ) );
 
DateTimeFormatter builder = new DateTimeFormatterBuilder()
        .appendLiteral("Day of Month is :")
        .appendValue(ChronoField.DAY_OF_MONTH)
        .appendLiteral(", Month is :")
        .appendValue(ChronoField.MONTH_OF_YEAR)
        .appendLiteral(", Year is : ")
        .appendValue(ChronoField.YEAR)
        .appendLiteral(", Time is :")
        .appendValue(ChronoField.HOUR_OF_DAY)
        .appendLiteral(":")
        .appendText(ChronoField.MINUTE_OF_HOUR, TextStyle.FULL_STANDALONE)
        .parseCaseSensitive()
        .toFormatter();
 
LocalDateTime localDateTime = LocalDateTime.now();
String date = localDateTime.format(builder);
System.out.println(date);

Bu yazıda, tarihler ve zamanlar arasındaki farklılaşma ve yeni tarih / zaman API’sı tarafından sunulan özelliklerin ve olanakların çoğunu açıklamaya çalıştım. Ama daha yazamadığım birçok özelliği mevcuttur. Java dokümantasyonunu okuyarak, bir yandan da örnekler yaparak öğrendiklerinizi pekiştirebilirsiniz. Ayrıca yazdığım test kodlarını githubdan çekebilirsiniz.

Kaynaklar

  • https://www.iso.org/iso-8601-date-and-time-format.html
  • https://docs.oracle.com/javase/tutorial/datetime/TOC.html
  • https://docs.oracle.com/javase/8/docs/api/java/time/package-summary.html
  • https://docs.oracle.com/javase/8/docs/api/java/time/temporal/package-summary.html
  • https://jcp.org/en/jsr/detail?id=310

2 yorum yapıldı “Java 8 : Date/Time API”

  1. android dedi ki:
    25 Mart 2020, 12:06

    ZonedDateTime kullanamıyorum. Api 26 dan sonrasını falan destekliyor. Zonet. Of now falan hata veriyor. İşin içinden bir türlü çıkamadım ltfen yardım. Tek istediğim telin saatini değil güncel saati alabilmek api 18 ve sonrası için.

    Cevapla
  2. Geri bildirim: Java 8 Yenilikleri – Bölüm 4 – Ömer Faruk Genç

Bir cevap yazın Cevabı iptal et

E-posta hesabınız yayımlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir

POPÜLER YAZILAR

  • Bir Yazılımcının Sırt Çantası
  • CI (Continuous integration) ve CD (Continuous Delivery/Deployment)
  • NullPointerException’dan Kaçış
  • Project : Lombok
  • İlk işime veda :(
  • JAR, WAR, EAR Üçlemesi
  • Yük Testi ve SoapUI
  • Mutable ve Immutable nedir ?
  • REST Mimarisi ve RESTful Servisler
  • Enumeration nedir ?

Ara

Son Yazılar

  • Apache Kafka
  • Postman API’ları Görselleştirme
  • MongoDB Cheat Sheet
  • Splunk 101 – Giriş
  • Yük Testi ve SoapUI
  • Modern Veri Tabanları
  • Senior Stajyer ?!
  • API Dokümantasyon Önemi ve Swagger
  • Kod Tekrarı(Code Duplication) ve DRY
  • Yapılacaklar : Kitap OKU

TAKİP ET

Koray PEKER
©2023 Koray PEKER