किसी स्ट्रिंग को दिनांक और समय के साथ एक विशेष बिंदु में पार्स करना (जावा इसे एक " Instant
" कहता है ) काफी जटिल है। जावा कई पुनरावृत्तियों में इससे निपट रहा है। नवीनतम एक, java.time
और java.time.chrono
, लगभग सभी जरूरतों को शामिल करता है ( टाइम डिलिशन :) को छोड़कर )।
हालांकि, यह जटिलता बहुत भ्रम पैदा करती है।
दिनांक पार्सिंग को समझने की कुंजी है:
किसी तिथि को पार्स करने के लिए जावा के पास इतने सारे तरीके क्यों हैं
- एक समय को मापने के लिए कई प्रणालियाँ हैं। उदाहरण के लिए, ऐतिहासिक जापानी कैलेंडर संबंधित सम्राट या राजवंश के शासनकाल के समय से प्राप्त हुए थे। फिर उदाहरण के लिए UNIX टाइमस्टैम्प है। सौभाग्य से, पूरी (व्यावसायिक) दुनिया उसी का उपयोग करने में कामयाब रही।
- ऐतिहासिक रूप से, विभिन्न कारणों से सिस्टम को / से स्विच किया जा रहा था । 1582 में जूलियन कैलेंडर से ग्रेगोरियन कैलेंडर तक। इसलिए इससे पहले 'पश्चिमी' तारीखों को अलग तरह से व्यवहार करने की आवश्यकता है।
- और निश्चित रूप से परिवर्तन एक बार में नहीं हुआ। क्योंकि कैलेंडर कुछ धर्मों के मुख्यालय से आया था और यूरोप के अन्य हिस्सों में अन्य आहारों पर विश्वास किया गया था, उदाहरण के लिए जर्मनी वर्ष 1700 तक स्विच नहीं करता था।
... और क्यों LocalDateTime
, ZonedDateTime
एट अल है। बहुत कठिन
कर रहे हैं समय क्षेत्र । एक समय क्षेत्र मूल रूप से पृथ्वी की सतह का एक "स्ट्राइप" * [1] है, जिसके अधिकारी उसी समय के नियमों का पालन करते हैं जब उसमें समय की भरपाई होती है। इसमें समर टाइम के नियम भी शामिल हैं।
समय क्षेत्र विभिन्न क्षेत्रों के लिए समय के साथ बदलते हैं, ज्यादातर इस बात पर आधारित होते हैं कि कौन किस पर विजय प्राप्त करता है। और एक समय क्षेत्र के नियम समय के साथ-साथ बदलते हैं ।
टाइम ऑफसेट हैं। यह समय क्षेत्र के समान नहीं है, क्योंकि एक समय क्षेत्र उदा "प्राग" हो सकता है, लेकिन इसमें समर टाइम ऑफसेट और विंटर टाइम ऑफसेट है।
यदि आपको टाइम ज़ोन के साथ टाइमस्टैम्प मिलता है, तो ऑफसेट अलग-अलग हो सकता है, यह उस वर्ष के किस हिस्से पर निर्भर करता है। लीप ऑवर के दौरान टाइमस्टैम्प का मतलब 2 अलग-अलग समय हो सकता है, इसलिए अतिरिक्त जानकारी के बिना, यह मज़बूती से नहीं हो सकता है। बदल दिया।
नोट: टाइमस्टैम्प से मेरा मतलब है "एक स्ट्रिंग जिसमें एक दिनांक और / या समय होता है, वैकल्पिक रूप से एक समय क्षेत्र और / या ऑफसेट के साथ।"
कई समय क्षेत्र निश्चित अवधि के लिए समान समय ऑफसेट साझा कर सकते हैं। उदाहरण के लिए, GMT / UTC टाइम ज़ोन "लंदन" टाइम ज़ोन के समान है, जब ग्रीष्मकालीन समय ऑफसेट प्रभाव में नहीं होता है।
इसे थोड़ा और जटिल बनाने के लिए (लेकिन यह आपके उपयोग के मामले के लिए बहुत महत्वपूर्ण नहीं है):
- वैज्ञानिक पृथ्वी के गतिशील का निरीक्षण करते हैं, जो समय के साथ बदलता है; उसके आधार पर, वे व्यक्तिगत वर्षों के अंत में सेकंड जोड़ते हैं। (तो
2040-12-31 24:00:00
एक मान्य दिनांक-समय हो सकता है।) यह मेटाडेटा के नियमित अपडेट की आवश्यकता है जो सिस्टम का उपयोग दिनांक रूपांतरणों को सही करने के लिए करता है। जैसे कि लिनक्स पर, आपको इन नए डेटा सहित जावा पैकेजों के नियमित अपडेट मिलते हैं।
अद्यतन हमेशा ऐतिहासिक और भविष्य के टाइमस्टैम्प दोनों के लिए पिछले व्यवहार को नहीं रखते हैं। तो यह हो सकता है कि कुछ समय क्षेत्र के बदलाव के आसपास दो टाइमस्टैम्प्स की पार्सिंग करना सॉफ्टवेयर के विभिन्न संस्करणों पर चलने पर अलग- अलग परिणाम दे सकता है । यह प्रभावित समय क्षेत्र और अन्य समय क्षेत्र के बीच तुलना करने के लिए भी लागू होता है।
क्या यह आपके सॉफ़्टवेयर में बग पैदा कर सकता है, कुछ टाइमस्टैम्प का उपयोग करने पर विचार करें, जिसमें इस तरह के जटिल नियम नहीं हैं, जैसे UNIX टाइमस्टैम्प ।
भविष्य की तारीखों के लिए 7 की वजह से, हम निश्चितता के साथ तारीखों को परिवर्तित नहीं कर सकते हैं। इसलिए, उदाहरण के लिए, वर्तमान पार्सिंग 8524-02-17 12:00:00
भविष्य के पार्सिंग से कुछ सेकंड का हो सकता है।
इसके लिए JDK की एपीआई समकालीन जरूरतों के साथ विकसित हुई
- प्रारंभिक जावा रिलीज़ में बस
java.util.Date
थोड़ा सा अनुभव था, यह मानते हुए कि अभी साल, महीना, दिन और समय है। यह जल्दी नहीं हुआ।
- इसके अलावा, डेटाबेस की जरूरतें अलग थीं, इसलिए यह बहुत शुरुआती
java.sql.Date
थी, इसकी अपनी सीमाएँ थीं।
- क्योंकि न तो विभिन्न कैलेंडर और समय क्षेत्रों को अच्छी तरह से कवर किया
Calendar
गया था , इसलिए एपीआई पेश किया गया था।
- यह अभी भी समय क्षेत्र की जटिलता को कवर नहीं करता था। और फिर भी, उपरोक्त एपीआई का मिश्रण वास्तव में काम करने के लिए एक दर्द था। इसलिए जैसे ही जावा डेवलपर्स ने वैश्विक वेब अनुप्रयोगों पर काम करना शुरू किया, पुस्तकालयों ने सबसे अधिक उपयोग के मामलों को लक्षित किया, जैसे कि JodaTime, जल्दी से लोकप्रिय हो गया। JodaTime लगभग एक दशक के लिए वास्तविक मानक था।
- लेकिन JDK ने JodaTime के साथ एकीकरण नहीं किया, इसलिए इसके साथ काम करना थोड़ा बोझिल था। इसलिए, इस मामले पर संपर्क करने के तरीके पर बहुत लंबी चर्चा के बाद, मुख्य रूप से JodaTime पर आधारित JSR-310 बनाया गया ।
जावा में इससे कैसे निपटें java.time
निर्धारित करें कि किस टाइमस्टैम्प को पार्स करना है
जब आप टाइमस्टैम्प स्ट्रिंग का उपभोग कर रहे हैं, तो आपको यह जानना होगा कि इसमें क्या जानकारी है। यह महत्वपूर्ण बिंदु है। यदि आपको यह अधिकार नहीं मिलता है, तो आप एक गुप्त अपवाद को समाप्त करते हैं जैसे "तत्काल नहीं बना सकते" या "ज़ोन ऑफ़सेट मिसिंग" या "अज्ञात ज़ोन आईडी" आदि।
क्या इसमें तारीख और समय समाहित है?
क्या यह एक समय ऑफसेट है?
एक समय ऑफसेट +hh:mm
हिस्सा है। कभी-कभी, यूनिवर्सल टाइम कोऑर्डिनेट या ग्रीनविच मीन टाइम के रूप में 'ज़ुलु समय' के रूप में +00:00
प्रतिस्थापित किया जा सकता है । ये समय क्षेत्र भी निर्धारित करते हैं।
इन टाइमस्टैम्प के लिए, आप उपयोग करते हैं ।Z
UTC
GMT
OffsetDateTime
क्या इसका कोई समय क्षेत्र है?
इन टाइमस्टैम्प के लिए, आप उपयोग करते हैं ZonedDateTime
।
ज़ोन या तो द्वारा निर्दिष्ट किया गया है
टाइम ज़ोन की सूची एक "TZ डेटाबेस" द्वारा संकलित है , जिसे ICAAN द्वारा समर्थित किया गया है।
ZoneId
जेवाडॉक के अनुसार , ज़ोन आईडी को किसी तरह Z
और ऑफसेट के रूप में भी निर्दिष्ट किया जा सकता है । मुझे यकीन नहीं है कि यह नक्शे वास्तविक क्षेत्रों में कैसे हैं। यदि टाइमस्टैम्प, जिसमें केवल एक टीबी है, एक घंटे के अंतराल में बदल जाता है, तो यह अस्पष्ट है, और व्याख्या का विषय है ResolverStyle
, नीचे देखें।
यदि यह न तो है, तो लापता संदर्भ ग्रहण या उपेक्षित है। और उपभोक्ता को तय करना होगा। तो यह रूप में पार्स करने की आवश्यकता है LocalDateTime
और परिवर्तित करने के लिए OffsetDateTime
याद आ रही जानकारी जोड़कर:
- आप मान सकते हैं कि यह यूटीसी का समय है। 0 घंटे के यूटीसी ऑफसेट जोड़ें।
- आप मान सकते हैं कि यह उस स्थान का एक समय है जहां रूपांतरण हो रहा है। सिस्टम के समय क्षेत्र को जोड़कर इसे रूपांतरित करें।
- आप उपेक्षा कर सकते हैं और बस इसका उपयोग कर सकते हैं । यह दो बार (देखें
Duration
) की तुलना या प्रतिस्थापित करने के लिए उदाहरण के लिए उपयोगी है , या जब आप नहीं जानते हैं और यह वास्तव में मायने नहीं रखता है (जैसे स्थानीय बस अनुसूची)।
आंशिक समय की जानकारी
- क्या टाइमस्टैम्प शामिल आधार पर, आप ले जा सकते हैं
LocalDate
, LocalTime
, OffsetTime
, MonthDay
, Year
, या YearMonth
इसे से बाहर।
यदि आपके पास पूरी जानकारी है, तो आप ए java.time.Instant
। यह आंतरिक रूप से OffsetDateTime
और के बीच कनवर्ट करने के लिए भी उपयोग किया जाता है ZonedDateTime
।
इसे पार्स करने का तरीका जानें
एक व्यापक प्रलेखन है, DateTimeFormatter
जिस पर दोनों टाइमस्टैम्प स्ट्रिंग और स्ट्रिंग को प्रारूपित कर सकते हैं।
पूर्व-निर्मित DateTimeFormatter
रों अधिककम सभी मानक टाइमस्टैम्प प्रारूपों को शामिल करना चाहिए। उदाहरण के लिए, ISO_INSTANT
पार्स कर सकते हैं 2011-12-03T10:15:30.123457Z
।
यदि आपके पास कुछ विशेष प्रारूप हैं, तो आप अपना स्वयं का DateTimeFormatter (जो कि एक पार्सर भी है) बना सकते हैं ।
private static final DateTimeFormatter TIMESTAMP_PARSER = new DateTimeFormatterBuilder()
.parseCaseInsensitive()
.append(DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SX"))
.toFormatter();
मैं स्रोत कोड को देखने की सलाह देता हूं DateTimeFormatter
और इसका उपयोग करने के तरीके के बारे में प्रेरित करता हूं DateTimeFormatterBuilder
। जब आप वहां हों, तो यह भी देख ResolverStyle
लें कि प्रारूप या अस्पष्ट जानकारी के लिए पार्सर LENIENT, SMART या STRICT है या नहीं।
TemporalAccessor
अब, लगातार गलती की जटिलता में जाना है TemporalAccessor
। यह आता है कि डेवलपर्स के साथ काम करने के लिए कैसे इस्तेमाल किया गया था SimpleDateFormatter.parse(String)
। सही, DateTimeFormatter.parse("...")
आपको देता है TemporalAccessor
।
// No need for this!
TemporalAccessor ta = TIMESTAMP_PARSER.parse("2011-... etc");
लेकिन, पिछले अनुभाग से ज्ञान से सुसज्जित, आप आसानी से उस प्रकार का पार्स कर सकते हैं, जिसकी आपको आवश्यकता है:
OffsetDateTime myTimestamp = OffsetDateTime.parse("2011-12-03T10:15:30.123457Z", TIMESTAMP_PARSER);
आपको वास्तव में DateTimeFormatter
दोनों की आवश्यकता नहीं है । जिस तरह से आप पार्स करना चाहते हैं, उसके parse(String)
तरीके हैं।
OffsetDateTime myTimestamp = OffsetDateTime.parse("2011-12-03T10:15:30.123457Z");
TemporalAccessor
यदि आप स्ट्रिंग में कौन सी जानकारी है, इसका एक अस्पष्ट विचार है, और रनटाइम के बारे में निर्णय लेना चाहते हैं, तो इसके बारे में , आप इसका उपयोग कर सकते हैं।
मुझे आशा है कि मैं आपकी आत्मा पर समझ के कुछ प्रकाश डाला :)
नोट: java.time
जावा 6 और 7 का बैकपोर्ट है : थ्रीटेन-बैकपोर्ट । Android के लिए इसमें तीनTENABP है ।
[१] सिर्फ इतना ही नहीं कि वे धारियाँ नहीं हैं, बल्कि कुछ अजीब चरम सीमाएँ भी हैं। उदाहरण के लिए, कुछ पड़ोसी प्रशांत द्वीपों में +14: 00 और -11: 00 समय क्षेत्र हैं। इसका मतलब है, कि एक द्वीप पर, 1 मई 3 बजे, दूसरे द्वीप पर अभी तक नहीं है, यह अभी भी 30 अप्रैल 12 बजे है (यदि मैं सही ढंग से गिना जाता हूं :))
ZonedDateTime
बजाय चाहते हैंLocalDateTime
। नाम प्रति-सहज है; एक विशिष्ट समय क्षेत्र के बजाय सामान्य रूप से किसी भी इलाके काLocal
मतलब है । जैसे, किसी वस्तु को समय रेखा से नहीं बांधा जाता है। अर्थ के लिए, समय रेखा पर एक निर्दिष्ट क्षण प्राप्त करने के लिए, आपको एक समय क्षेत्र लागू करना चाहिए।LocalDateTime