CodeGym /Kurslar /JAVA 25 SELF /ZonedDateTime, Instant, saat qurşaqları ilə iş

ZonedDateTime, Instant, saat qurşaqları ilə iş

JAVA 25 SELF
Səviyyə , Dərs
Mövcuddur

1. Saat qurşağı anlayışı

Dünyada çoxlu saat qurşaqları var: Minskdə günorta olanda, Nyu-Yorkda hələ səhər, Tokioda isə artıq axşam olur. Əgər tarixi və vaxtı saat qurşağını nəzərə almadan saxlasanız, asanlıqla çaşqınlıq yaranar: məsələn, serveriniz Almaniyadadır, istifadəçi isə Vladivostokdadırsa, "2025-06-01 12:00" vaxtının göstərilməsi hər biri üçün tamamilə fərqli məna daşıyacaq.

Saat qurşağı (timezone) — bu, konkret region üçün “yerli” zamanı almaq üçün Qrinviç vaxtına (UTC) nə qədər əlavə etmək və ya çıxmaq lazım olduğunu müəyyən edən qaydadır.

Javada saat qurşaqları ilə işləmək üçün ZoneId sinfi istifadə olunur. Zon identifikatorlarının bir neçə nümunəsi:

  • "Europe/Minsk"
  • "UTC"
  • "America/New_York"
  • "Asia/Tokyo"

Bu niyə vacibdir?

  • Müxtəlif ölkələrdən olan istifadəçilər üçün vaxtın düzgün göstərilməsi.
  • Hadisələrin vaxtının düzgün qeydi (məsələn, jurnallaşdırma, bilet bronu, son tarixlər).
  • Yay/qış vaxtına keçidin nəzərə alınması (təşəkkürlər, Avropa!).

2. ZonedDateTime — saat qurşağını nəzərə alan tarix və vaxt

ZonedDateTime — tarix, vaxt saat qurşağı məlumatını saxlayan sinifdir. Bu, LocalDateTime kimidir, sadəcə, əlavə olaraq hansı regionda olduğunu da “bilir”.

ZonedDateTime yaratma

Sistem saat qurşağında cari tarix və vaxt

import java.time.ZonedDateTime;

ZonedDateTime now = ZonedDateTime.now();
System.out.println(now); // Məsələn: 2025-06-01T15:30:00+03:00[Europe/Minsk]

Konkret saat qurşağında vaxt

import java.time.ZoneId;

ZonedDateTime MinskTime = ZonedDateTime.now(ZoneId.of("Europe/Minsk"));
ZonedDateTime newYorkTime = ZonedDateTime.now(ZoneId.of("America/New_York"));

System.out.println("Minsk: " + MinskTime);
System.out.println("Nyu-York: " + newYorkTime);

LocalDateTime-dən yaratma

import java.time.LocalDateTime;

LocalDateTime meeting = LocalDateTime.of(2025, 6, 1, 18, 0);
ZonedDateTime meetingInMinsk = meeting.atZone(ZoneId.of("Europe/Minsk"));
System.out.println(meetingInMinsk); // 2025-06-01T18:00+03:00[Europe/Minsk]

Saat qurşağını almaq və təyin etmək

ZoneId tokyoZone = ZoneId.of("Asia/Tokyo");
ZonedDateTime tokyoTime = ZonedDateTime.now(tokyoZone);
System.out.println("Tokio: " + tokyoTime);

Zonalar arasında çevirmə: withZoneSameInstant()

Bəzən eyni hadisənin başqa zonada necə göründüyünü bilmək lazım olur. Bunun üçün withZoneSameInstant() istifadə edirik:

ZonedDateTime MinskMeeting = ZonedDateTime.of(2025, 6, 1, 18, 0, 0, 0, ZoneId.of("Europe/Minsk"));
ZonedDateTime newYorkMeeting = MinskMeeting.withZoneSameInstant(ZoneId.of("America/New_York"));

System.out.println("Minskdə görüş vaxtı: " + MinskMeeting);
System.out.println("Eyni hadisə Nyu-Yorkda: " + newYorkMeeting);

Diqqət: withZoneSameInstant() zamanı elə çevirir ki, başqa zonada eyni ana uyğun gəlsin. Əgər withZoneSameLocal() istifadə etsəniz, tarix və vaxt eyni qalacaq, yalnız zona dəyişəcək — bu isə demək olar ki, həmişə səhvdir!

3. Instant — mütləq zaman nöqtəsi

Instant — saat qurşağından asılı olmayaraq mütləq zaman anını təmsil edən sinifdir. Texniki olaraq, bu, 1 yanvar 1970-ci ildən Qrinviç üzrə (UTC) keçən saniyələrin və nanosaniyələrin sayıdır. Vaxtın pasportu olsaydı — Instant onun nömrəsi olardı.

Instant yaratma

import java.time.Instant;

Instant now = Instant.now();
System.out.println(now); // Məsələn: 2025-06-01T12:30:00.123Z

Z hərfinə diqqət yetirin — bu “Zulu time”, yəni UTC deməkdir.

Unix epoxasından bəri saniyələrdən yaratma

Instant fromEpoch = Instant.ofEpochSecond(1685616000L);
System.out.println(fromEpoch); // 2023-06-01T00:00:00Z

InstantZonedDateTime/LocalDateTime çevrilməsi

ZonedDateTime-dən Instant

ZonedDateTime zoned = ZonedDateTime.now();
Instant instant = zoned.toInstant();
System.out.println(instant);

Instant-dən ZonedDateTime

ZoneId zone = ZoneId.of("Europe/Minsk");
ZonedDateTime fromInstant = Instant.now().atZone(zone);
System.out.println(fromInstant);

Instant-dən LocalDateTime

import java.time.LocalDateTime;
import java.time.Instant;
import java.time.ZoneId;

LocalDateTime local = LocalDateTime.ofInstant(Instant.now(), ZoneId.of("Europe/Minsk"));
System.out.println(local);

4. Təcrübə: müxtəlif saat qurşaqlarında cari zaman, zonalar arasında çevirmə

Müxtəlif saat qurşaqlarında cari vaxtı əldə etmək

Minsk, Nyu-York və Tokioda cari vaxtı göstərən kiçik bir tətbiq yazaq:

import java.time.ZonedDateTime;
import java.time.ZoneId;

public class TimeZonesDemo {
    public static void main(String[] args) {
        ZonedDateTime Minsk = ZonedDateTime.now(ZoneId.of("Europe/Minsk"));
        ZonedDateTime newYork = ZonedDateTime.now(ZoneId.of("America/New_York"));
        ZonedDateTime tokyo = ZonedDateTime.now(ZoneId.of("Asia/Tokyo"));

        System.out.println("Minsk:    " + Minsk);
        System.out.println("Nyu-York:  " + newYork);
        System.out.println("Tokio:     " + tokyo);
    }
}

Zonalar arasında vaxtın çevrilməsi

Tutaq ki, Minskdə saat 18:00-a təyin olunmuş bir hadisəniz var. Bu, Nyu-Yorkda və Tokioda saat neçəyə düşəcək?

import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.ZonedDateTime;

public class MeetingTime {
    public static void main(String[] args) {
        LocalDateTime eventTime = LocalDateTime.of(2025, 6, 1, 18, 0);
        ZonedDateTime minskEvent = eventTime.atZone(ZoneId.of("Europe/Minsk"));

        ZonedDateTime newYorkEvent = minskEvent.withZoneSameInstant(ZoneId.of("America/New_York"));
        ZonedDateTime tokyoEvent = minskEvent.withZoneSameInstant(ZoneId.of("Asia/Tokyo"));

        System.out.println("Minskdə görüş:   " + minskEvent);
        System.out.println("Nyu-Yorkda:        " + newYorkEvent);
        System.out.println("Tokioda:            " + tokyoEvent);
    }
}

LocalDateTimeZonedDateTime-ə və geri çevirmək

Local → Zoned:

import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.ZonedDateTime;

LocalDateTime localTime = LocalDateTime.of(2025, 6, 1, 14, 0);
ZonedDateTime zonedTime = localTime.atZone(ZoneId.of("Europe/Minsk"));
System.out.println(zonedTime);

Zoned → Local:

LocalDateTime extracted = zonedTime.toLocalDateTime();
System.out.println(extracted);

5. Vacib qeydlər və nüanslar

Niyə yalnız LocalDateTime saxlamaq olmaz

LocalDateTime — bu, sadəcə saat qurşağı olmadan tarix və vaxtdır. Çoxlu biznes məntiqi üçün bu kifayət deyil! Məsələn, "2025-06-01 12:00"LocalDateTime kimi saxlasanız, Minsk və Nyu-York istifadəçiləri üçün bu, real vaxtda tamamilə fərqli anlar olacaq.

Həmişə mütləq vaxtı (məsələn, Instant) saxlayın, və ya hadisə konkret zonaya bağlıdırsa, zonalı vaxtı (ZonedDateTime) istifadə edin. LocalDateTime yalnız “üzən” tarixlərlə işləyərkən uyğundur (məsələn, doğum günü — sutka vaxtını və zonanı nəzərə almadan).

Yay/qış vaxtına keçidlə bağlı problemlər

Saat qurşaqları — yalnız UTC-yə nisbətdə yerdəyişmə deyil, həm də yay/qış vaxtına keçid qaydalarıdır. Məsələn, bəzi ölkələrdə müəyyən gündə saatlar irəli və ya geri çəkilir — və siz yalnız LocalDateTime saxlayırsınızsa, bu vaxtın ümumiyyətlə mövcud olub-olmadığını bilməyəcəksiniz.

“Vaxtda boşluq” nümunəsi:

  • ABŞ-da mart ayında gecə saat 2:00-da saatlar 3:00-a keçirilir.
  • Nyu-Yorkda "2025-03-10 02:30" vaxtı mövcud olmayıb!

ZonedDateTime ilə işləyərkən bu kimi sürprizlərdən qorxmağa ehtiyac yoxdur: kitabxana özü vaxtın düzgünlüyünü yoxlayır.

Sxem: LocalDateTime, ZonedDateTime, Instant necə əlaqəlidir

graph TD
    A["LocalDateTime 
(tarix + vaxt, zona yoxdur)"] -->|+ ZoneId| B["ZonedDateTime
(tarix + vaxt + zona)"] B -->|"toInstant()"| C["Instant
(mütləq vaxt, UTC)"] C -->|"atZone(ZoneId)"| B B -->|"toLocalDateTime()"| A

6. ZonedDateTimeInstant ilə işləyərkən tipik səhvlər

Səhv №1: Qlobal hadisələr üçün LocalDateTime istifadə etmək.
Əgər müxtəlif ölkələrdən olan istifadəçilərin görüş tarix və vaxtını LocalDateTime kimi saxlasanız, hər kəs öz “12:00”ını görəcək, halbuki söhbət müxtəlif anlardan gedir. Qlobal hadisələr üçün ZonedDateTime və ya Instant istifadə edin.

Səhv №2: Sətiri parse edərkən saat qurşağını nəzərə almamaq.
"2025-06-01T12:00:00" sətirini zona göstərmədən parse etsəniz, nəticə LocalDateTime olacaq, ZonedDateTime deyil. ZonedDateTime almaq üçün zonalı sətirlərdən istifadə edin və ya zonanı açıq şəkildə əlavə edin.

Səhv №3: Zonalar arasında yanlış çevirmə.
withZoneSameInstant() əvəzinə withZoneSameLocal() istifadə etmək səhv vaxta gətirib çıxara bilər. Başqa zonada eyni anı almaq istəyirsinizsə, həmişə withZoneSameInstant() istifadə edin.

Səhv №4: Yay/qış vaxtına keçidi nəzərə almamaq.
Keçid sərhədində hadisələr planlaşdırırsınızsa, mütləq ZonedDateTime istifadə edin və kitabxanaya etibar edin — o, bütün keçidləri və “boşluqları” bilir.

Səhv №5: ZonedDateTime-ları zonanı nəzərə almadan müqayisə etmək.
Fərqli zonalara məxsus, lakin eyni lokal vaxta malik iki ZonedDateTime realda müxtəlif anları təmsil edə bilər. Müqayisə üçün toInstant() istifadə edin.

Şərhlər
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION