Java Time API

Hər kəsə salam.

Java 9-un çıxmasına qısa zaman qalmasını nəzərə alaraq Java 8 ilə gələn Time API haqda qısa bir məqalə yazmaq istədim.

Yeni API-ın gəlmə səbəbi java.util.Date və Calendar-ın bir çox çatışmazlıqlarının olmasıdır.

java.util.Date thrad safe deyildi və bunun gətirdiyi problemlər vardı.

java.util.Date -in elə də zəngin API dizaynı yox idi. Belə ki il 1900-dan, aylar 1-dən, günlər isə 0-dan başlayırdı – heç bir eynilik yox idi. Plus zamanla bir başa bağlı metodları az idi.

Fərqli ölkələrə görə zaman problemini aradan qaldırmaq üçün onlarla sətr kod yazmalı oldurduq.

Bu kimi səbəblərdən dolayı external kitabxanalardan istifadə edirdik.

Java 8 ilə gələn Time API-da bu problemlər ardan qaldırıldı: Date Time API dəyişməzdir (immutable) yəni Thread safe-dir, fərqli zaman qurşaqlarını tənzimləmək çox rahatdır.

Date Time API – java.time. package-nin daxilindədir və qısa olaraq iki hissəyə ayıra bilərik:

  • Local – time zona funksiyalarının olmadığı
  • Zoned – müxtəlif tima zonalarla işləmək üçün.

Time API-də olan funksiyaları qısa olaraq başlıqlarına görə izah edəsi olsaq:

  • of – static yaratma metodu.
  • parse – parse (string à time) üçün olan metod.
  • get – obyektdən hər hansı qiyməti almaq.
  • is – nəyinsə doğru olub olmadığını yoxlamaq üçün metod.
  • with – setter metodunun thread safe versiyası.
  • plus – obyektə zaman əlavə etmək.
  • minus – obyektdən zaman çıxmaq.
  • to – obyekti başqa bir obyektə çevirmək (convert).
  • at – obyekti başqa biri ilə birləşdirmək.

 

Nəzəri hissəni bitirib işin maraqlı tərəfinə keçmək istəyirəm. Time API-ı necə istifadə edək?

Local Date – Time API

LocalDate, LocalTime və LocalDateTime classları zaman qurşaqları vacib olmadığı zaman işimizi sadələşdirir. İlk öncə kodumuzu yazaq, ardından izahına keçərik.


import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.Month;
import java.time.temporal.ChronoField;

/**
* Created by Mustafa Aslanov on 25/7/16.
*/
public class MyDateTimeAPITest {

public static void main(String... gogo) {
startTestLocalDateAndTime();
}

public static void startTestLocalDateAndTime(){
//İndiki tarix və zaman
LocalDateTime localDateTime = LocalDateTime.now();

System.out.println("Hal hazırda: " +localDateTime);

LocalDate localDate = localDateTime.toLocalDate();
LocalTime localTime = localDateTime.toLocalTime();

System.out.println("İndiki tarıx: " + localDate +
"\nHal hazırda saat: " + localTime);

//Setter əvəzinə with 20 mart tarixini set edirik yeni obyektə:
LocalDateTime localDateTime2 = localDateTime.withMonth(3).with(ChronoField.DAY_OF_MONTH, 20);
//20 Mart 2016
System.out.println("Local Date Time 2: "+localDateTime2);

Month month = localDateTime.getMonth();
int day = localDateTime.getDayOfMonth();
//İngilis azərbaycan qarışığı olacaq amma nə etmək olar. Azərbaycan dilində yoxdu aylar :(
System.out.println("Hal hazırda " + month + " ayınını " + day);

//Of metodu ilə yeni bir tarix yaradırıq. Yeni ile 1 dəqiqə qalır :)
LocalDateTime localDateTime3 = LocalDateTime.of(2016, Month.DECEMBER, 31, 23, 59);
System.out.println("Yeni ilə 1 dəqiqə: " + localDateTime3);

//Tarixdən ay gün saat və s. çıxa və ya əlavə edə bilərik.
LocalDate ldKecmish = localDate.minusDays(10);
LocalDate ldGelecek = localDate.plusDays(10);

System.out.println("10 gün keçmiş: " + ldKecmish +
"\n10 gün gələcək: "+ldGelecek);

String myDate = "2012-12-21";
LocalDate localDateParse = LocalDate.parse(myDate);

System.out.println("String -dən parse edilmiş tarix: " + localDateParse);
}

}

 

LocalDateTime –dan LocalTime-a və LocalDate-ə keçmək mümkündür. toLocalDate(), toLocalTime() buna görədir.

Time API-da setter metodu olmadığı üçün əvəzinə with…() istifadə edirik. Burda day, month, year filan ola bilər və ya heç bir şey yazmayıb ChronoFiled-dan istədiyimizi seçə bilərik. with() bizə dəyişdiyimiz tarixin yeni bir obyektini qaytarır.

of() metodu ilə özümüz istədiyimiz tarixi yaradırıq. Sadəcə olaraq ili, ayı, günü, saatı, dəqiqəni göstərməliyik.

parse()  metodu String formatında olan məlumatı tarixə çevirmək üçün işimizə yarayır.

Burada olan bütün metodlar hər 3 class –dada mövcuddur və ümumi məntiqi eynidir.

Programımızı işlətdikdə aşağıdakı nəticəni alırıq:

Hal hazırda: 2016-07-25T17:35:54.757

İndiki tarıx: 2016-07-25

Hal hazırda saat: 17:35:54.757

Local Date Time 2: 2016-03-20T17:35:54.757

Hal hazırda JULY ayınını 25

Yeni ilə 1 dəqiqə: 2016-12-31T23:59

10 gün keçmiş: 2016-07-15

10 gün gələcək: 2016-08-04

String -dən parse edilmiş tarix: 2012-12-21

Zoned Date – Time API

Müxtəlif zaman qurşaqlarında zamanların fərqliliyini aradaq qaldırmaq üçün istifadə edirik:

 


public void startTestZonedDateAndTime(){
LocalDateTime localDateTime = LocalDateTime.now();

ZoneId zoneIdDefault = ZoneId.systemDefault();
ZonedDateTime zonedDateTime = localDateTime.atZone(zoneIdDefault);

//və ya bunu qısaca bu cür də yaza bilərik.
ZonedDateTime zonedDateTime1 = ZonedDateTime.now();
System.out.println("Local Date Time-dan: " + zonedDateTime);
System.out.println("now() funksiyası ilə: " + zonedDateTime1);

ZoneId zoneId = ZoneId.of("Asia/Hong_Kong");
zonedDateTime1 = zonedDateTime1.withZoneSameInstant(zoneId);

System.out.println("Hong Kongda zaman: " + zonedDateTime1);

zonedDateTime = zonedDateTime.withZoneSameLocal(ZoneId.of("Asia/Baku"));
System.out.println("Bakı vaxtı: " + zonedDateTime);

}

 

ZoneId.systemDefault() əməliyyat sistemində mövcud zonanı götürür. Bundan sonra LocalDateTime –dan ZonedDateTime-a keçmək mümkündür. Bunu qısa olaraq Local –da olduğu kimidə .now() funksiyası ilə də edə bilərik.

.withZoneSameInstant və .withZoneSameLocal funkisyaları arasındakı fərq sadə şəkildə:

  • Istant verdiyimiz oblyekti alaraq yeni daxil etdiyimiz zonaya uyğun zamanı – saatı toplayıb və ya çıxıb yeni obyekti qaytarır.
  • Local isə bizim verdiyimiz obyektə daxil etdiyimiz zonanı set edib geri qaytarır (Zamanı dəyişmədən).

Ümumilikdə LocalDateTime –da istifadə etdiyimiz digər bütün funksiyalar ZonedDateTime –da eynidir.

Programımızı işlətdikdə:

 

Local Date Time-dan: 2016-07-31T21:00:44.072+04:00[GMT+04:00]

now() funksiyası ilə: 2016-07-31T21:00:44.073+04:00[GMT+04:00]

Hong Kongda zaman: 2016-08-01T01:00:44.073+08:00[Asia/Hong_Kong]

Bakı vaxtı: 2016-07-31T21:00:44.072+05:00[Asia/Baku]

 

Sistemdə olan bütün zonaId-ləri zaman qurşağı ilə birlikdə görmək üçün:

 


//Bütün zonaların siyahısı və offset-ləri
Set<String> zones = ZoneId.getAvailableZoneIds();
List<String> listZones = new ArrayList<>(zones);
Collections.sort(listZones);
for (String zone : listZones){
ZoneId zoneId = ZoneId.of(zone);
ZonedDateTime zdt = localDateTime.atZone(zoneId);
ZoneOffset offset = zdt.getOffset();

String out = String.format("%35s %10s%n", zoneId, offset);
System.out.println(out);
}

 

Output:

Africa/Abidjan          Z

Africa/Accra          Z

Africa/Addis_Ababa     +03:00

Africa/Algiers     +01:00

 

Period və Duration:

  • Period – tarixlər arasındakı fərqi tapmaq
  • Duration – saatlar arasındakı fərqi tapmaq üçündür.

 


public void startTestPeriodAndDuration(){
LocalDate localDate1 = LocalDate.now();
System.out.println("Hal hazırda: " + localDate1);

//İndiki zamanın üzərinə 4 gün 6 həfət 1 il əlavə edirik.
LocalDate localDate2 = localDate1.plusDays(4).plusWeeks(6).plus(1 , ChronoUnit.YEARS);
System.out.println("Gələcək: " + localDate2);

//iki tarix arasındakı fərqi alırıq. ld1 başlanğıc ld2 bitiş tarixidir.
Period period = Period.between(localDate1, localDate2);
System.out.println("Fərq: " + period.getYears() + " - il, " + period.getMonths() +
" - ay, " + period.getDays() + " - gün");

LocalTime localTime1 = LocalTime.now();
System.out.println("Hal hazırda saat: " + localTime1);

Duration birSaat = Duration.ofHours(1);

//1 saat əlavə edirik indiki zamana. Bunu duration-la etmək olur.
LocalTime localTime2 = localTime1.plus(birSaat);
System.out.println("1 saat sonra: " + localTime2);

Duration duration = Duration.between(localTime1, localTime2);

System.out.println(duration);
System.out.println("Saniyələrlə fərq: " + duration.getSeconds());
}

 

Duration-la işlədiyimizdə bir məsələyə diqqət yetirmək lazımdır. Əgər iki fərqli günün saatını LocalTime ilə müqayisə ediriksə yalnız saata görə müqayisə aparacağı üçün nəticəni fərqli ala bilərsiniz. Məsələn:

Deyəkki bu gün saat 22:00 –dı və üstünə 4 saat gəlirik. Edir gecə 2. Bunları müqayisə etdikdə duration bizə -20 saat qaytaracaq.

Bunun qarşısını almaq üçün LocalDateTime –dan istifadə edə bilərik.

Programımızı işlətdikdə nəticə:

Hal hazırda: 2016-07-31

Gələcək: 2017-09-15

Fərq: 1 – il, 1 – ay, 15 – gün

Hal hazırda saat: 21:58:40.788

1 saat sonra: 22:58:40.788

PT1H

Saniyələrlə fərq: 3600

 

Burada saniyədən başqa başqa nano saniyənidə seçə bilərik. İki saat arasındakı nano saniyə. Timer-da filan istifadə olunur 🙂

Util Date

Java.time yeni gəldiyi üçün hələdə util.Date –dən tez tez istifadə edirik. Programda lazım olduqda Local və ya Zoned Date Time-dan java.util.Date –ə və əksinə rahatlıqla keçə bilərik. Bunun üçün Java 8 –də toInstant() metodu əlavə edilib Date və Calendara.

 


public void utilDate(){
//Yeni Date yaradırıq.
Date date = new Date();
System.out.println("Util Date: " + date.toString());

// Date-dən milli saniyələrlə instant alırıq.
Instant instant = date.toInstant();

LocalDateTime localDateTime = LocalDateTime.ofInstant(instant, ZoneId.systemDefault());

System.out.println("LocalDateTime: " + localDateTime);
}

 

Output:

Util Date: Sun Jul 31 22:23:35 GMT+04:00 2016

LocalDateTime: 2016-07-31T22:23:35.696

Bilirəm bəzilərinizin output –dakı görünüş xoşunuza gəlmədi. Bunu düzəltmək üçün DateTimeFormatter –dən istifadə edərək formatı istədiyimiz cür dəyişə bilərik. O da qalsın sonrakı yazıma 🙂 bu günlük bu qədər yetər məncə.

Ümid edirəm faydalı olmuşdur.

 

Source:

Github

Ref:

Oracle

Səs: +10. Bəyənilsin Zəifdir

Müəllif: Mustafa Aslanov

Şərhlər ( 2 )

  1. Salam. Mustafa bəy, məqalə üçün təşəkkür edirik. Davamlı olmasını arzulayırıq..

Şərh yazın