ZonedDateTime java.time पैकेज से एक अपरिवर्तनीय (immutable) वर्ग है जो दिनांक और समय को टाइम ज़ोन जानकारी (ZoneId) के साथ संग्रहीत करता है। LocalDateTime के विपरीत, ZonedDateTime समयरेखा पर एक क्षण की असंदिग्ध रूप से पहचान करता है। Oracle Java 17 (2024) विनिर्देश के अनुसार, यह वर्ग IANA Time Zone Database के ज़ोन नियमों के माध्यम से डेलाइट सेविंग टाइम (DST) संक्रमण को सही ढंग से संभालता है।
मुख्य बिंदु
ZonedDateTime java.time पैकेज की प्रमुख कक्षाओं में से एक है, जो पूर्ण टाइम ज़ोन जानकारी के साथ दिनांक और समय का प्रतिनिधित्व करता है। यह तीन घटकों को जोड़ता है: LocalDateTime (दिनांक और समय), ZoneId (ज़ोन पहचानकर्ता), और ZoneOffset (UTC के सापेक्ष ऑफ़सेट)।
LocalDateTime के विपरीत, जो बिना टाइम ज़ोन बाइंडिंग के केवल वॉल-क्लॉक टाइम संग्रहीत करता है, ZonedDateTime एक क्षण की असंदिग्ध रूप से पहचान करता है। विभिन्न टाइम ज़ोन में दो समान LocalDateTime इंस्टेंस समय में अलग-अलग क्षणों का प्रतिनिधित्व करते हैं। दो समान ZonedDateTime इंस्टेंस — एक ही क्षण।
यह वर्ग पूरी तरह से अपरिवर्तनीय और थ्रेड-सेफ है। सभी अंकगणितीय संक्रियाएँ एक नया ऑब्जेक्ट लौटाती हैं। ZonedDateTime ChronoZonedDateTime इंटरफ़ेस को लागू करता है और इसका उपयोग वहाँ किया जा सकता है जहाँ Java में ज़ोनल समय कार्य की आवश्यकता होती है।
Oracle Java 17 विनिर्देशों के अनुसार, ZonedDateTime IANA Time Zone Database के किसी भी ज़ोन के साथ काम करने का समर्थन करता है, जिसमें 600 से अधिक टाइम ज़ोन शामिल हैं।
मुख्य अंतर — ZonedDateTime में टाइम ज़ोन होता है, जबकि LocalDateTime में नहीं होता। यह मूलभूत अंतर प्रत्येक वर्ग के उपयोग के दायरे को निर्धारित करता है।
LocalDateTime का उपयोग स्थानीय घटनाओं के लिए किया जाता है: संगीत कार्यक्रम का समय, कक्षा अनुसूची, जन्म तिथि। यदि कोई घटना मास्को में 15:00 बजे होती है, तो LocalDateTime बिना किसी बाइंडिंग के 15:00 रिकॉर्ड करेगा। यदि आप सर्वर को न्यूयॉर्क में स्थानांतरित करते हैं, तो समय 15:00 ही रहेगा — लेकिन यह एक अलग भौतिक क्षण होगा।
ZonedDateTime का उपयोग वैश्विक डेटा के लिए किया जाता है: सर्वर लॉग, API में टाइमस्टैम्प, अंतर्राष्ट्रीय बैठकें। यदि कोई बैठक 15:00 MSK पर निर्धारित है, तो ZonedDateTime समय और ज़ोन दोनों को संरक्षित करेगा। न्यूयॉर्क में, यह 8:00 EST के रूप में सही ढंग से प्रदर्शित होगा। Baeldung (2024) के अनुसार, LocalDateTime और ZonedDateTime के बीच चुनाव तिथियों के साथ काम करते समय सबसे आम वास्तु निर्णय है।
व्यावहारिक नियम: यदि डेटा एक क्षेत्र के लिए संग्रहीत किया जाता है — LocalDateTime का उपयोग करें। यदि डेटा टाइम ज़ोन सीमाओं को पार करता है — ZonedDateTime का उपयोग करें। यदि आपको एक पूर्ण क्षण का प्रतिनिधित्व करने की आवश्यकता है — Instant का उपयोग करें।
java.time में टाइम ज़ोन ZoneId वर्ग द्वारा दर्शाया जाता है। ZoneId “महाद्वीप/क्षेत्र” प्रारूप में एक ज़ोन पहचानकर्ता है, उदाहरण के लिए “Europe/Moscow”, “America/New_York”, “Asia/Tokyo”। ZoneId को स्थैतिक विधि of(String zoneId) के माध्यम से या सिस्टम डिफ़ॉल्ट टाइम ज़ोन के माध्यम से प्राप्त किया जाता है।
ZoneId दो प्रकारों में विभाजित है: fixed offset (निश्चित ऑफ़सेट, जैसे “+03:00”) और region-based (क्षेत्रीय ज़ोन, जैसे “Europe/London”)। क्षेत्रीय ज़ोन में डेलाइट सेविंग टाइम संक्रमण नियम और ऐतिहासिक परिवर्तन होते हैं। Fixed offset केवल एक निश्चित ऑफ़सेट है।
किसी विशिष्ट क्षण में ZoneId का वर्तमान ऑफ़सेट प्राप्त करने के लिए, getRules() विधि का उपयोग किया जाता है, जो ZoneRules लौटाता है। ZoneRules में किसी दिए गए ज़ोन के लिए सभी संक्रमण और ऑफ़सेट होते हैं। यह सही DST हैंडलिंग के लिए प्रमुख तंत्र है।
सभी टाइम ज़ोन tzdata फ़ाइलों (IANA Time Zone Database) के माध्यम से JDK के साथ शामिल किए जाते हैं और नियमित रूप से अपडेट किए जाते हैं। Android पर, tzdata संस्करण Google Play Services के माध्यम से सिस्टम अपडेट पर निर्भर करता है।
ZonedDateTime को कई तरीकों से बनाया जा सकता है। सबसे सरल now() है, जो सिस्टम टाइम ज़ोन में वर्तमान समय लौटाता है। now(ZoneId) वैरिएंट आपको निर्दिष्ट ज़ोन में वर्तमान समय प्राप्त करने की अनुमति देता है।
of(LocalDateTime, ZoneId) विधि स्थानीय समय और ज़ोन से ZonedDateTime बनाती है। of(int year, int month, int dayOfMonth, int hour, int minute, int second, int nanoOfSecond, ZoneId zone) वैरिएंट घटकों से बनाता है।
LocalDateTime को atZone(ZoneId) विधि के माध्यम से ZonedDateTime में परिवर्तित किया जा सकता है। Instant — Instant.atZone(ZoneId) के माध्यम से। Date — Date.toInstant().atZone(ZoneId) के माध्यम से।
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)
मुख्य रूपांतरण विधि withZoneSameInstant(ZoneId) है। यह ZonedDateTime को उसी क्षण को बनाए रखते हुए दूसरे टाइम ज़ोन में परिवर्तित करती है। उदाहरण के लिए, 15:00 MSK → 8:00 EST। withZoneSameLocal(ZoneId) विधि स्थानीय समय को बनाए रखते हुए ज़ोन बदलती है — यह एक अलग क्षण देती है।
UTC के सापेक्ष ऑफ़सेट प्राप्त करने के लिए, getOffset() विधि का उपयोग किया जाता है, जो ZoneOffset लौटाती है। ZoneOffset ZoneId का एक उपवर्ग है जो “+HH:mm” या “-HH:mm” प्रारूप में एक निश्चित ऑफ़सेट दर्शाता है।
Instant में रूपांतरण toInstant() विधि के माध्यम से किया जाता है। Instant समय में एक पूर्ण क्षण है, जो टाइम ज़ोन से स्वतंत्र है। विपरीत रूपांतरण 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"))
डेलाइट सेविंग टाइम संक्रमण दो समस्याएँ पैदा करते हैं: अंतराल (gaps) और अतिव्यापन (overlaps)। अंतराल वसंत में होता है जब घड़ियाँ आगे बढ़ाई जाती हैं — एक निश्चित समय मौजूद नहीं होता। अतिव्यापन शरद ऋतु में होता है जब घड़ियाँ पीछे हटाई जाती हैं — एक ही समय दो बार होता है।
ZonedDateTime समाधान (resolve) रणनीति के माध्यम से इन स्थितियों को संभालता है। अंतराल के दौरान कोई ऑब्जेक्ट बनाते समय, java.time स्वचालित रूप से समय को ऑफ़सेट राशि से स्थानांतरित करता है। अतिव्यापन के दौरान बनाते समय, पहला विकल्प (संक्रमण से पहले) चुना जाता है। इस व्यवहार को withZoneSameInstant के माध्यम से बदला जा सकता है।
आप zone.getRules().isDaylightSavings(instant) के माध्यम से जाँच सकते हैं कि कोई समय DST में है या नहीं। getOffset() विधि किसी दिए गए क्षण के लिए वास्तविक ऑफ़सेट दिखाती है, और getRules().getDaylightSavings(instant) मिलीसेकंड में DST समायोजन राशि दिखाती है।
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 ऑफ़सेट: $dstAmount")
}
}
ZonedDateTime को फ़ॉर्मेट करने के लिए DateTimeFormatter का उपयोग किया जाता है। मानक ISO प्रारूप में दिनांक, समय और ऑफ़सेट शामिल है: “2026-07-21T15:30:00+03:00[Europe/Moscow]”। पूर्वनिर्धारित प्रारूप: ISO_ZONED_DATE_TIME, ISO_OFFSET_DATE_TIME, ISO_INSTANT।
स्थानीयकृत आउटपुट के लिए, DateTimeFormatter.ofLocalizedDateTime(FormatStyle) का उपयोग करें। FormatStyle SHORT, MEDIUM, LONG, FULL हो सकता है। LONG में ज़ोन का नाम (“MSK”) शामिल होता है, FULL में पूरा नाम (“Moscow Standard Time”) शामिल होता है।
महत्वपूर्ण: ZonedDateTime के साथ एक स्ट्रिंग को पार्स करते समय, प्रारूप में ज़ोन या ऑफ़सेट जानकारी होनी चाहिए। यदि ज़ोन निर्दिष्ट नहीं है, तो LocalDateTime.parse() और फिर atZone() का उपयोग करें।
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
)
पहला उदाहरण — उपयोगकर्ता को उसके स्थानीय टाइम ज़ोन में मीटिंग का समय दिखाना। सर्वर UTC में ZonedDateTime भेजता है, क्लाइंट डिवाइस के स्थानीय टाइम ज़ोन में कनवर्ट करता है।
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)
}
दूसरा उदाहरण — टाइम ज़ोन को ध्यान में रखते हुए अगली घटना तक के समय की गणना करना। हम सर्वर समय के लिए ZonedDateTime और अंतर की गणना के लिए Duration.between() का उपयोग करते हैं।
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"
}
तीसरा उदाहरण — Retrofit API के साथ काम करना। सर्वर ज़ोन के साथ ISO-8601 स्ट्रिंग लौटाता है। हम ZonedDateTime में कनवर्ट करने के लिए एक कस्टम डीसेरियलाइज़र का उपयोग करते हैं।
data class EventResponse(
@JsonAdapter(ZonedDateTimeAdapter::class)
val eventTime: ZonedDateTime
)
class ZonedDateTimeAdapter : JsonAdapter<ZonedDateTime>() {
override fun fromJson(reader: JsonReader): ZonedDateTime? {
return ZonedDateTime.parse(
reader.nextString()
)
}
}
पहली गलती — सर्वर कोड में ZoneId.systemDefault() का उपयोग करना। सर्वर का टाइम ज़ोन क्लाइंट से भिन्न हो सकता है, और सर्वर पर सिस्टम ज़ोन का उपयोग करने से गलत गणनाएँ होती हैं। हमेशा स्पष्ट रूप से ज़ोन निर्दिष्ट करें या संदर्भ के रूप में UTC का उपयोग करें।
दूसरी गलती — अवधि की गणना करते समय DST को अनदेखा करना। Duration.between() संक्रमणों को सही ढंग से संभालता है, लेकिन यदि आप मैन्युअल रूप से टाइमस्टैम्प घटाते हैं, तो डेलाइट सेविंग टाइम 1 घंटे की त्रुटि पैदा कर सकता है। मैन्युअल गणित के बजाय ChronoUnit.HOURS.between() का उपयोग करें।
तीसरी गलती — withZoneSameInstant और withZoneSameLocal के बीच भ्रम। पहला क्षण को बनाए रखते हुए ज़ोन बदलता है — समय स्थानांतरित होता है। दूसरा स्थानीय समय को बनाए रखते हुए ज़ोन बदलता है — क्षण बदलता है। SonarSource (2024) के अनुसार, गलत विधि चुनना सबसे आम गलतियों में से एक है।
चौथी गलती — यह मान लेना कि डिवाइस का टाइम ज़ोन हमेशा उपयोगकर्ता के टाइम ज़ोन के समान है। उपयोगकर्ता यात्रा कर रहा हो सकता है और उम्मीद करता है कि ऐप वर्तमान ज़ोन के बजाय उसके “गृह” टाइम ज़ोन में समय दिखाए। इस मामले में, इंटरफ़ेस के माध्यम से ज़ोन चयन प्रदान करें।
अक्सर पूछे जाने वाले प्रश्न
ZonedDateTime में एक क्षेत्रीय ज़ोन पहचानकर्ता (उदा., “Europe/Moscow”) होता है और यह DST को संभालता है। OffsetDateTime क्षेत्रीय नियमों के बिना केवल एक निश्चित ऑफ़सेट (+03:00) संग्रहीत करता है। डेटाबेस भंडारण के लिए, OffsetDateTime की अनुशंसा की जाती है।
ZonedDateTime.now(ZoneOffset.UTC) या Instant.now().atZone(ZoneOffset.UTC) का उपयोग करें। दोनों विकल्प शून्य ऑफ़सेट के साथ वर्तमान क्षण लौटाते हैं। एक सरल टाइमस्टैम्प के लिए, ज़ोन बाइंडिंग के बिना Instant.now() का उपयोग करें।
हाँ, लेकिन एक कस्टम एडाप्टर आवश्यक है। Gson डिफ़ॉल्ट रूप से ZonedDateTime का समर्थन नहीं करता है। Moshi Rfc3339DateJsonAdapter के माध्यम से इसका समर्थन करता है। Jackson के लिए Kotlinx Serialization या JavaTimeModule लाइब्रेरी का उपयोग करने की अनुशंसा की जाती है।
java.time स्वचालित रूप से समय को ऑफ़सेट राशि से आगे स्थानांतरित करता है। उदाहरण के लिए, यदि 02:30 मौजूद नहीं है जब घड़ियाँ 03:00 पर आगे बढ़ती हैं, तो ZonedDateTime 03:30 पर एक ऑब्जेक्ट बनाएगा। आप ZoneRules.getTransition(instant) के माध्यम से अंतराल की जाँच कर सकते हैं।
JDBC 4.2 OffsetDateTime का समर्थन करता है लेकिन सीधे ZonedDateTime का नहीं। ZonedDateTime में एक क्षेत्रीय ज़ोन होता है जिसका SQL में कोई समकक्ष नहीं है। OffsetDateTime या Instant संग्रहीत करने की अनुशंसा की जाती है, और ज़ोन को एक अलग कॉलम में संग्रहीत करें।
सारांश
हम एक मोबाइल एप्लिकेशन टर्नकी विकसित करेंगे
IT Sectr 2017 से स्टार्टअप और व्यवसायों के लिए iOS और Android एप्लिकेशन बनाता है। हम आपको सलाह देंगे और सर्वोत्तम समाधान प्रस्तावित करेंगे।
यह भी पढ़ें