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 və 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
Instant ↔ ZonedDateTime/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);
}
}
LocalDateTime-ı ZonedDateTime-ə 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. ZonedDateTime və Instant 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.
GO TO FULL VERSION