ZonedDateTime — bu nima, vaqt mintaqalari va vaqt bilan ishlash

Muallif: IT Sectr Nashr etilgan: 2026-07-13 O'qish vaqti: 10 daq

ZonedDateTime — java.time paketidagi immutable sinf, sana va vaqtni vaqt mintaqasi (ZoneId) haqidagi ma'lumot bilan birga saqlaydi. LocalDateTime-dan farqli o'laroq, ZonedDateTime vaqt shkalasidagi momentni aniq belgilaydi. Oracle Java 17 (2024) spetsifikatsiyasiga ko'ra, sinf IANA Time Zone Database ma'lumotlar bazasidagi mintaqa qoidalari orqali yozgi vaqtga (DST) o'tishni to'g'ri qayta ishlaydi.

Asosiy

  • ZonedDateTime — immutable sinf, sana, vaqt va vaqt mintaqasini (ZoneId) bitta obyektda birlashtiradi.
  • LocalDateTime-dan farqli o'laroq, ZonedDateTime vaqt shkalasidagi momentni aniq belgilaydi va global tizimlar uchun mos keladi.
  • Sinf IANA Time Zone Database qoidalariga muvofiq yozgi vaqtga (DST) o'tishni avtomatik qayta ishlaydi.
  • Vaqt mintaqalari o'rtasida konvertatsiya qilish uchun withZoneSameInstant(ZoneId) metodidan foydalaniladi.
  • ZonedDateTime ni ma'lumotlar bazalarida saqlash OffsetDateTime yoki TIMESTAMP WITH TIME ZONE orqali tavsiya etiladi.

ZonedDateTime nima?

ZonedDateTime — java.time paketining asosiy sinflaridan biri, sana va vaqtni vaqt mintaqasi haqida to'liq ma'lumot bilan ifodalaydi. U uch komponentni birlashtiradi: LocalDateTime (sana va vaqt), ZoneId (mintaqa identifikatori) va ZoneOffset (UTC ga nisbatan siljish).

LocalDateTime dan farqli o'laroq, u faqat devor vaqti (wall-clock time) ni mintaqaga bog'lanmagan holda saqlaydi, ZonedDateTime momentni aniq belgilaydi. Turli vaqt mintaqalaridagi ikkita bir xil LocalDateTime turli vaqt momentlarini ifodalaydi. Ikkita bir xil ZonedDateTime — bir xil momentni.

Sinf to'liq immutable va thread-safe. Barcha arifmetik amallar yangi obyekt qaytaradi. ZonedDateTime ChronoZonedDateTime interfeysini amalga oshiradi va Java da mintaqaviy vaqt bilan ishlash talab qilinadigan har qanday joyda ishlatilishi mumkin.

Oracle Java 17 spetsifikatsiyasiga ko'ra, ZonedDateTime 600 dan ortiq vaqt mintaqasini o'z ichiga olgan IANA Time Zone Database dan istalgan mintaqa bilan ishlashni qo'llab-quvvatlaydi.

ZonedDateTime vs LocalDateTime: farqi nimada?

Asosiy farq — ZonedDateTime vaqt mintaqasini o'z ichiga oladi, LocalDateTime esa yo'q. Bu fundamental farq har bir sinfning qo'llanish doirasini belgilaydi.

LocalDateTime mahalliy hodisalar uchun ishlatiladi: konsert vaqti, dars jadvali, tug'ilgan sana. Agar hodisa Moskvada soat 15:00 da sodir bo'lsa, LocalDateTime 15:00 ni bog'lanmagan holda qayd etadi. Agar serverni Nyu-Yorkka ko'chirsangiz, vaqt 15:00 bo'lib qoladi — lekin bu endi boshqa fizik moment.

ZonedDateTime global ma'lumotlar uchun qo'llaniladi: server loglari, API dagi vaqt belgilari, xalqaro uchrashuvlar. Agar uchrashuv soat 15:00 MSK ga belgilangan bo'lsa, ZonedDateTime ham vaqtni, ham mintaqani saqlaydi. Nyu-Yorkda bu to'g'ri tarzda 8:00 EST sifatida ko'rsatiladi. Baeldung (2024) ga ko'ra, LocalDateTime va ZonedDateTime o'rtasidagi tanlov sanalar bilan ishlashda eng keng tarqalgan arxitektura qaroridir.

Amaliy qoida: agar ma'lumotlar bir mintaqa uchun saqlansa — LocalDateTime dan foydalaning. Agar ma'lumotlar vaqt mintaqalari chegaralarini kesib o'tsa — ZonedDateTime dan foydalaning. Agar mutlaq momentni uzatish kerak bo'lsa — Instant dan foydalaning.

java.time da vaqt mintaqasi qanday ishlaydi?

java.time da vaqt mintaqasi ZoneId sinfi bilan ifodalanadi. ZoneId — “continent/region” formatidagi mintaqa identifikatori, masalan “Europe/Moscow”, “America/New_York”, “Asia/Tokyo”. ZoneId of(String zoneId) statik metodi yoki standart tizim vaqt mintaqasi orqali olinadi.

ZoneId ikki turga bo'linadi: fixed offset (qattiq siljish, masalan “+03:00”) va region-based (mintaqaviy zonalar, masalan “Europe/London”). Mintaqaviy zonalar yozgi vaqtga o'tish qoidalari va tarixiy o'zgarishlarni o'z ichiga oladi. Fixed offset — faqat qattiq siljish.

Muayyan bir momentda ZoneId ning joriy siljishini olish uchun getRules() metodidan foydalaniladi, u ZoneRules ni qaytaradi. ZoneRules berilgan mintaqa uchun barcha o'tishlar va siljishlarni o'z ichiga oladi. Bu DST ni to'g'ri qayta ishlash uchun asosiy mexanizmdir.

Barcha vaqt mintaqalari JDK bilan tzdata (IANA Time Zone Database) fayllari orqali ta'minlanadi va muntazam yangilanadi. Android da tzdata versiyasi Google Play Services orqali tizim yangilanishlariga bog'liq.

ZonedDateTime yaratish

ZonedDateTime yaratishning bir necha usuli bor. Eng soddasi — now(), tizim vaqt mintaqasidagi joriy vaqtni qaytaradi. now(ZoneId) varianti belgilangan mintaqada joriy vaqtni olish imkonini beradi.

of(LocalDateTime, ZoneId) metodi mahalliy vaqt va mintaqadan ZonedDateTime yaratadi. of(int year, int month, int dayOfMonth, int hour, int minute, int second, int nanoOfSecond, ZoneId zone) varianti — komponentlardan.

LocalDateTime atZone(ZoneId) metodi orqali ZonedDateTime ga aylantirilishi mumkin. Instant — Instant.atZone(ZoneId) orqali. Date — Date.toInstant().atZone(ZoneId) orqali.

kotlin
val moscowZone = ZoneId.of("Europe/Moscow")

val nowInMoscow = ZonedDateTime.now(moscowZone)

val fromComponents = ZonedDateTime.of(
    2026, 7, 21, 15, 30, 0, 0, moscowZone
)

val fromLocal = LocalDateTime.now().atZone(moscowZone)

val fromInstant = Instant.now().atZone(moscowZone)

Vaqt mintaqalari o'rtasida konvertatsiya

Asosiy konvertatsiya metodi — withZoneSameInstant(ZoneId). ZonedDateTime ni bir xil momentni saqlagan holda boshqa vaqt mintaqasiga o'zgartiradi. Masalan, 15:00 MSK → 8:00 EST. withZoneSameLocal(ZoneId) metodi mintaqani o'zgartiradi, mahalliy vaqtni saqlaydi — bu boshqa momentni beradi.

UTC ga nisbatan siljishni olish uchun getOffset() metodidan foydalaniladi, u ZoneOffset ni qaytaradi. ZoneOffset — “+HH:mm” yoki “-HH:mm” formatida qattiq siljishni ifodalovchi ZoneId ning vorisidir.

Instant ga aylantirish toInstant() metodi orqali amalga oshiriladi. Instant — vaqt mintaqasidan mustaqil mutlaq vaqt momenti. Teskari aylantirish — Instant.atZone(ZoneId).

kotlin
val moscow = ZonedDateTime.of(
    2026, 7, 21, 15, 0, 0, 0,
    ZoneId.of("Europe/Moscow")
)

val newYork = moscow.withZoneSameInstant(
    ZoneId.of("America/New_York")
)

val utcInstant = moscow.toInstant()
val backToMoscow = utcInstant.atZone(ZoneId.of("Europe/Moscow"))

Yozgi vaqt bilan ishlash (DST)

Yozgi vaqtga o'tish ikkita muammo yaratadi: bo'shliqlar (gap) va qoplanishlar (overlap). Bo'shliq bahorda soatlar oldinga surilganda paydo bo'ladi — ma'lum vaqt mavjud emas. Qoplanish — kuzda vaqt orqaga surilganda, bir xil vaqt ikki marta mavjud bo'ladi.

ZonedDateTime bu holatlarni resolve strategiyasi orqali qayta ishlaydi. Bo'shliq vaqtida obyekt yaratilganda, java.time avtomatik ravishda vaqtni siljish miqdoriga oldinga suradi. Qoplanish vaqtida yaratilganda, birinchi variant (o'zgarishdan oldin) tanlanadi. Xatti-harakatni withZoneSameInstant orqali o'zgartirish mumkin.

Vaqtning DST mintaqasida ekanligini zone.getRules().isDaylightSavings(instant) orqali tekshirish mumkin. getOffset() metodi ma'lum moment uchun joriy siljishni ko'rsatadi, getRules().getDaylightSavings(instant) esa — DST tuzatishining millisekundlardagi miqdorini.

kotlin
fun checkDST(zdt: ZonedDateTime) {
    val rules = zdt.getZone().getRules()
    val instant = zdt.toInstant()

    if (rules.isDaylightSavings(instant)) {
        val dstAmount = rules.getDaylightSavings(instant)
        Log.d("DST", "DST siljishi: $dstAmount")
    }
}

ZonedDateTime formatlash

ZonedDateTime ni formatlash uchun DateTimeFormatter dan foydalaniladi. Standart ISO formati sana, vaqt va siljishni o'z ichiga oladi: “2026-07-21T15:30:00+03:00[Europe/Moscow]”. Oldindan belgilangan formatlar: ISO_ZONED_DATE_TIME, ISO_OFFSET_DATE_TIME, ISO_INSTANT.

Mahalliylashtirilgan formatlash uchun DateTimeFormatter.ofLocalizedDateTime(FormatStyle) dan foydalaning. FormatStyle SHORT, MEDIUM, LONG, FULL bo'lishi mumkin. LONG mintaqa nomini (“MSK”), FULL — to'liq nomni (“Moscow Standard Time”) o'z ichiga oladi.

Muhim: ZonedDateTime bilan satrni tahlil qilishda format mintaqa yoki siljish haqida ma'lumotni o'z ichiga olishi kerak. Agar mintaqa ko'rsatilmagan bo'lsa, LocalDateTime.parse() va keyin atZone() dan foydalaning.

kotlin
val zdt = ZonedDateTime.now(ZoneId.of("Europe/Moscow"))

val iso = zdt.format(DateTimeFormatter.ISO_ZONED_DATE_TIME)

val custom = DateTimeFormatter
    .ofPattern("dd.MM.yyyy HH:mm z")
val formatted = zdt.format(custom)

val parsed = ZonedDateTime.parse(
    "2026-07-21T15:30:00+03:00",
    DateTimeFormatter.ISO_OFFSET_DATE_TIME
)

Android da ZonedDateTime: amaliy misollar

Birinchi misol — foydalanuvchiga o'z vaqt mintaqasida uchrashuv vaqtini ko'rsatish. Server ZonedDateTime ni UTC da qaytaradi, mijoz qurilmaning mahalliy vaqt mintaqasiga o'tkazadi.

kotlin
fun displayMeetingTime(
    serverUtc: ZonedDateTime
): String {
    val deviceZone = ZoneId.systemDefault()
    val localTime = serverUtc.withZoneSameInstant(deviceZone)
    val formatter = DateTimeFormatter
        .ofPattern("dd.MM.yyyy HH:mm z")
    return localTime.format(formatter)
}

Ikkinchi misol — vaqt mintaqasini hisobga olgan holda keyingi hodisagacha bo'lgan vaqtni hisoblash. Server vaqti uchun ZonedDateTime va farqni hisoblash uchun Duration.between() dan foydalanamiz.

kotlin
fun timeUntilEvent(eventTime: ZonedDateTime): String {
    val now = ZonedDateTime.now()
    val duration = Duration.between(now, eventTime)

    val hours = duration.toHours()
    val minutes = duration.toMinutes() % 60
    return "Remaining $hours h $minutes min"
}

Uchinchi misol — Retrofit API bilan ishlash. Server ISO-8601 formatida mintaqa bilan satr qaytaradi. ZonedDateTime ga aylantirish uchun maxsus deserializatordan foydalanamiz.

kotlin
data class EventResponse(
    @JsonAdapter(ZonedDateTimeAdapter::class)
    val eventTime: ZonedDateTime
)

class ZonedDateTimeAdapter : JsonAdapter<ZonedDateTime>() {
    override fun fromJson(reader: JsonReader): ZonedDateTime? {
        return ZonedDateTime.parse(
            reader.nextString()
        )
    }
}

Vaqt mintaqalari bilan ishlashdagi xatolar

Birinchi xato — server kodida ZoneId.systemDefault() dan foydalanish. Serverning vaqt mintaqasi mijoznikidan farq qilishi mumkin va serverda tizim mintaqasidan foydalanish noto'g'ri hisob-kitoblarga olib keladi. Har doim mintaqani aniq ko'rsating yoki UTC ni etalon sifatida ishlating.

Ikkinchi xato — davomiylikni hisoblashda DST ni e'tiborsiz qoldirish. Duration.between() o'tishlarni to'g'ri qayta ishlaydi, lekin timestamp larni qo'lda ayirsangiz, yozgi vaqtga o'tish 1 soatlik xato berishi mumkin. Qo'lda matematika o'rniga ChronoUnit.HOURS.between() metodlaridan foydalaning.

Uchinchi xato — withZoneSameInstant va withZoneSameLocal o'rtasidagi chalkashlik. Birinchisi mintaqani o'zgartiradi, momentni saqlaydi — vaqt siljiydi. Ikkinchisi mintaqani o'zgartiradi, mahalliy vaqtni saqlaydi — moment o'zgaradi. Noto'g'ri metod tanlash SonarSource (2024) ga ko'ra eng keng tarqalgan xatolardan biridir.

To'rtinchi xato — qurilmaning vaqt mintaqasi har doim foydalanuvchining vaqt mintaqasi bilan bir xil deb taxmin qilish. Foydalanuvchi sayohat qilishi mumkin va dastur vaqtni joriy emas, balki uning “uy” mintaqasida ko'rsatishini kutishi mumkin. Bunday holda, interfeys orqali mintaqa tanlashni ta'minlash kerak.

Tez-tez so'raladigan savollar

ZonedDateTime va OffsetDateTime o'rtasidagi farq nima?

ZonedDateTime mintaqaviy mintaqa identifikatorini (masalan “Europe/Moscow”) o'z ichiga oladi va DST ni qayta ishlaydi. OffsetDateTime faqat qattiq siljishni (+03:00) mintaqaviy qoidalarsiz saqlaydi. Ma'lumotlar bazasida saqlash uchun OffsetDateTime tavsiya etiladi.

ZonedDateTime orqali UTC da joriy vaqtni qanday olish mumkin?

ZonedDateTime.now(ZoneOffset.UTC) yoki Instant.now().atZone(ZoneOffset.UTC) dan foydalaning. Ikkala variant ham nol siljish bilan joriy momentni qaytaradi. Oddiy vaqt belgisi uchun mintaqaga bog'lanmagan holda Instant.now() dan foydalaning.

ZonedDateTime ni Gson yoki Moshi orqali seriyalash mumkinmi?

Ha, lekin maxsus adapter talab qilinadi. Gson ZonedDateTime ni standart holatda qo'llab-quvvatlamaydi. Moshi — Rfc3339DateJsonAdapter adapteri orqali qo'llab-quvvatlaydi. Jackson uchun Kotlinx Serialization yoki JavaTimeModule kutubxonasidan foydalanish tavsiya etiladi.

Vaqt DST bo'shlig'iga tushganda vaziyatni qanday hal qilish kerak?

java.time avtomatik ravishda vaqtni siljish miqdoriga oldinga suradi. Masalan, agar soat 02:30 03:00 ga o'tishda mavjud bo'lmasa, ZonedDateTime 03:30 obyektini yaratadi. Bo'shliq mavjudligini ZoneRules.getTransition(instant) orqali tekshirish mumkin.

Nega ZonedDateTime SQL ma'lumotlar bazalari uchun tavsiya etilmaydi?

JDBC 4.2 OffsetDateTime ni qo'llab-quvvatlaydi, lekin ZonedDateTime ni to'g'ridan-to'g'ri qo'llab-quvvatlamaydi. ZonedDateTime SQL da analogi bo'lmagan mintaqaviy zonani o'z ichiga oladi. OffsetDateTime yoki Instant saqlash, zonani esa alohida ustunda saqlash tavsiya etiladi.

Xulosa

  • ZonedDateTime — vaqt mintaqasi bilan sana va vaqt uchun immutable sinf, IANA Time Zone Database orqali DST ni to'g'ri qayta ishlaydi.
  • LocalDateTime dan asosiy farq — mintaqaning mavjudligi, bu ZonedDateTime ni vaqt momentining aniq identifikatoriga aylantiradi.
  • Mintaqalar o'rtasida konvertatsiya qilish uchun withZoneSameInstant() dan foydalaning, u momentni saqlaydi, withZoneSameLocal emas.
  • Yozgi vaqtga o'tishda java.time o'rnatilgan mintaqa qoidalari orqali bo'shliqlar va qoplanishlarni avtomatik hal qiladi.
  • Ma'lumotlar bazasida saqlash uchun OffsetDateTime dan foydalaning yoki Instant va ZoneId ni alohida saqlang.
  • Android da ZonedDateTime ni qurilmaning mahalliy vaqtiga aylantirish uchun ZoneId.systemDefault() ni withZoneSameInstant bilan birga ishlating.
  • JSON seriyalash uchun maxsus adapter talab qilinadi — Kotlinx Serialization yoki Jackson JavaTimeModule dan foydalaning.

Biz kalit topshirig'i bilan mobil ilovani ishlab chiqamiz

IT Sectr 2017-yildan beri startaplar va korxonalar uchun iOS va Android ilovalarini yaratadi. Biz sizga maslahat beramiz va eng yaxshi yechimni taklif qilamiz.

Loyihani muhokama qilish

Shuningdek o'qing