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 — 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.
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 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 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.
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)
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).
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 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.
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 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.
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
)
Birinchi misol — foydalanuvchiga o'z vaqt mintaqasida uchrashuv vaqtini ko'rsatish. Server ZonedDateTime ni UTC da qaytaradi, mijoz qurilmaning mahalliy vaqt mintaqasiga o'tkazadi.
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.
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.
data class EventResponse(
@JsonAdapter(ZonedDateTimeAdapter::class)
val eventTime: ZonedDateTime
)
class ZonedDateTimeAdapter : JsonAdapter<ZonedDateTime>() {
override fun fromJson(reader: JsonReader): ZonedDateTime? {
return ZonedDateTime.parse(
reader.nextString()
)
}
}
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 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.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.
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.
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.
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
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.