Java Date & Time API में क्या गलत है? [बन्द है]


105

बहुत बार मैं जावा Dateऔर अन्य दिनांक-समय-संबंधित कक्षाओं पर नकारात्मक प्रतिक्रिया देता हूं । .NET डेवलपर होने के नाते, मैं पूरी तरह से (उनका इस्तेमाल किए बिना) समझ नहीं सकता, वास्तव में उनके साथ क्या गलत है।

क्या कोई इस पर कुछ प्रकाश डाल सकता है?


जवाबों:


142

आह, जावा Dateवर्ग। शायद किसी भी भाषा में कुछ भी न करने के सर्वोत्तम उदाहरणों में से एक, कहीं भी। मै कहाँ से शुरू करू?

JavaDoc को पढ़ने से शायद ऐसा लगता है कि डेवलपर्स को वास्तव में कुछ अच्छे विचार मिले हैं। यह यूटीसी और जीएमटी के बीच की लंबाई में अंतर के बारे में बताता है , इस तथ्य के बावजूद कि दोनों के बीच का अंतर मूल रूप से लीप सेकंड है (जो बहुत कम होता है )।

हालांकि, डिज़ाइन निर्णय वास्तव में एक अच्छी तरह से डिज़ाइन किए गए एपीआई होने के किसी भी विचार को बर्बाद करने के लिए बिछाते हैं। यहाँ कुछ पसंदीदा गलतियाँ हैं:

  • सहस्राब्दी के अंतिम दशक में डिजाइन किए जाने के बावजूद, यह 1900 के बाद से दो अंकों के रूप में है। शाब्दिक लाखों वर्कअराउंड जावा संसार में इस प्रतिबंधात्मक निर्णय के परिणामस्वरूप 1900+ (या 1900-) कर रहे हैं।
  • महीनों को शून्य अनुक्रमित किया जाता है, जो एक सरणी के महीनों के शानदार असामान्य मामले को पूरा करने के लिए और तेरह तत्व सरणी के साथ नहीं रहते हैं, जिनमें से पहला एक है null। नतीजतन, हमारे पास 0..11 (और आज वर्ष 109 का 11 वां महीना है)। स्ट्रिंग में कनवर्ट करने के लिए महीनों पर ++ और - की समान संख्या होती है।
  • वे म्यूट हैं । परिणामस्वरूप, किसी भी समय आप एक तारीख वापस देना चाहते हैं (उदाहरण के लिए संरचना के रूप में), आपको तिथि ऑब्जेक्ट के बजाय उस तिथि का क्लोन वापस करने की आवश्यकता है (क्योंकि अन्यथा, लोग आपकी संरचना को म्यूट कर सकते हैं)।
  • Calendar'ठीक' इस के लिए बनाया गया है, वास्तव में एक ही गलतियों बनाता है। वे अभी भी उत्परिवर्ती हैं।
  • Dateएक का प्रतिनिधित्व करता है DateTime, लेकिन SQL भूमि में उन लोगों के लिए स्थगित करने के लिए, एक और उपवर्ग है java.sql.Date, जो एक ही दिन का प्रतिनिधित्व करता है (हालांकि इसके साथ जुड़े एक समयक्षेत्र के बिना)।
  • कोई TimeZoneएस के साथ संबद्ध नहीं हैं Date, और इसलिए पर्वतमाला (जैसे कि 'पूरे दिन') को अक्सर आधी रात-आधी रात के रूप में दर्शाया जाता है (अक्सर कुछ मनमाने समय में)

अंत में, यह ध्यान देने योग्य है कि लीप सेकंड आमतौर पर एक अच्छी प्रणाली की घड़ी के खिलाफ खुद को सही करता है जिसे एक घंटे के भीतर एनटीपी के साथ अपडेट किया जाता है (लिंक देखें)। दो लीप सेकंड (हर छह महीने में, प्रत्येक कुछ वर्षों में व्यावहारिक रूप से) की शुरूआत में एक सिस्टम के चालू रहने और चलने की संभावना बहुत ही कम है, विशेष रूप से इस तथ्य पर विचार करते हुए कि आपको समय-समय पर अपने कोड के नए संस्करणों को फिर से तैयार करना है। । यहां तक ​​कि एक गतिशील भाषा का उपयोग करते हुए जो कक्षाओं को पुनर्जन्म करता है या एक WAR इंजन की तरह कुछ भी क्लास स्पेस को प्रदूषित करेगा और अंततः पर्मगेन से बाहर चला जाएगा।


43

JSR 310 , जिसने जावा 8 में java.time के साथ पुराने डेट-टाइम क्लासेस को दबा दिया था, मूल JSR में खुद को सही ठहराता है:

2.5 प्रस्तावित विनिर्देश द्वारा जावा समुदाय की क्या जरूरत होगी?

वर्तमान में जावा एसई की दो अलग-अलग तिथि और समय एपीआई हैं - java.util.Date और java.util.Calendar। दोनों APIs को वेब डेवलपर्स और फ़ोरम पर जावा डेवलपर्स द्वारा उपयोग करने में लगातार मुश्किल बताया जाता है। विशेष रूप से, दोनों महीनों के लिए एक शून्य-सूचकांक का उपयोग करते हैं, जो कई कीड़े का कारण है। कैलेंडर भी कई वर्षों से कई बग और प्रदर्शन के मुद्दों से ग्रस्त है, मुख्य रूप से आंतरिक रूप से दो अलग-अलग तरीकों से अपने राज्य को संग्रहीत करने के कारण।

एक क्लासिक बग (4639407) ने कुछ तिथियों को कैलेंडर ऑब्जेक्ट में बनाए जाने से रोका। कोड का एक अनुक्रम लिखा जा सकता है जो कुछ वर्षों में एक तारीख बना सकता है लेकिन दूसरों में नहीं, कुछ उपयोगकर्ताओं को अपनी सही जन्म तारीखों को दर्ज करने से रोकने का प्रभाव पड़ता है। यह कैलेंडर वर्ग द्वारा केवल गर्मियों में एक घंटे के दिन के समय की बचत के लाभ की अनुमति देने के कारण हुआ था, जब ऐतिहासिक रूप से यह द्वितीय विश्व युद्ध के समय के आसपास 2 घंटे था। हालांकि यह बग अब तय हो गया है, अगर भविष्य में किसी देश ने गर्मियों में तीन घंटे के लिए दिन के उजाले की बचत का समय शुरू करने का विकल्प चुना, तो कैलेंडर वर्ग फिर से टूट जाएगा।

वर्तमान जावा एसई एपीआई भी बहु-थ्रेडेड वातावरण में ग्रस्त है। अपरिवर्तनीय वर्गों को स्वाभाविक रूप से थ्रेड-सुरक्षित माना जाता है क्योंकि उनका राज्य नहीं बदल सकता है। हालाँकि, दिनांक और कैलेंडर दोनों ही परिवर्तनशील हैं, जिन्हें प्रोग्रामर को क्लोनिंग और स्पष्ट रूप से फैलाने पर विचार करने की आवश्यकता होती है। इसके अलावा, DateTimeFormat में थ्रेड-सेफ्टी की कमी व्यापक रूप से ज्ञात नहीं है, और थ्रेडिंग मुद्दों को ट्रैक करने के लिए कई कठिन का कारण रहा है।

साथ ही जावा एसई की डेटटाइम के लिए जिन वर्गों के साथ समस्याएं हैं, उनके पास अन्य अवधारणाओं के मॉडलिंग के लिए कोई कक्षाएं नहीं हैं। गैर-समय-क्षेत्र की तारीखों या समय, अवधि, अवधि और अंतराल का जावा एसई में कोई वर्ग प्रतिनिधित्व नहीं है। नतीजतन, डेवलपर्स अक्सर यूनिट को निर्दिष्ट करने वाले javadoc के साथ समय की अवधि का प्रतिनिधित्व करने के लिए एक इंट का उपयोग करते हैं।

एक व्यापक तारीख और समय मॉडल की कमी के परिणामस्वरूप कई सामान्य ऑपरेशन भी पेचीदा हो जाते हैं, जो उन्हें होने चाहिए। उदाहरण के लिए, दो तिथियों के बीच दिनों की संख्या की गणना वर्तमान में एक विशेष रूप से कठिन समस्या है।

यह जेएसआर तिथियों और समय (और समय क्षेत्रों के साथ), अवधि और समय अवधि, अंतराल, स्वरूपण और पार्सिंग सहित एक पूर्ण तिथि और समय मॉडल की समस्या से निपटेगा।


28
  • दिनांक उदाहरण उत्परिवर्तनीय होते हैं , जो लगभग हमेशा असुविधाजनक होता है।
  • उनका दोहरा स्वभाव है। वे एक टाइमस्टैम्प और एक कैलेंडर तिथि दोनों का प्रतिनिधित्व करते हैं। यह पता चला है कि तारीखों पर गणना करते समय यह समस्याग्रस्त है।
  • कैलेंडर डेटा के संख्यात्मक निरूपण कई मामलों में प्रति-सहज होते हैं। उदाहरण के लिए: getMonth()शून्य-आधारित है, getYear()1900-आधारित है (अर्थात, वर्ष 2009 को 109 के रूप में दर्शाया गया है)।
  • वे एक कार्यक्षमता की बहुत याद कर रहे हैं जो आप एक Dateवर्ग से उम्मीद करते हैं ।

13

मैं आपके लिए महसूस करता हूं ... एक पूर्व .NET प्रोग्रामर के रूप में, मैंने एक ही सवाल पूछा था, .NET में टाइम एपीआई (टाइमपासंस, ऑपरेटर ओवरलोडिंग) बहुत सुविधाजनक है।

सबसे पहले, एक विशिष्ट तिथि बनाने के लिए, आप या तो एक पदावनत एपीआई का उपयोग करते हैं, या:

Calendar c = Calendar.getInstance();
c.set(2000, 31, 12)

एक दिन घटाना करने के लिए आप जैसे बुरे काम करते हैं

Date firstDate = ...
Calendar c = Calendar.getInstance();
c.setTime(fistDate);
c.add(Calendar.DATE,-1);
Date dayAgo = c.getTime();

या खराब

Date d = new Date();
Date d2 = new Date(d.getTime() - 1000*60*60*24);

यह जानने के लिए कि दो तिथियों (दिनों / हफ्तों / महीनों) में कितना समय बीत गया ... यह और भी बुरा हो जाता है

हालाँकि , अपाचे से डेट यूटिल्सorg.apache.commons.lang.time.DateUtils कुछ सुविधाजनक तरीके प्रदान करते हैं और मैंने हाल ही में केवल उनका उपयोग करके खुद को पाया

जैसा कि ब्रेबस्टर ने लिखा, जोदा टाइम एक अच्छा बाहरी पुस्तकालय भी है, लेकिन अपाचे कुछ और की तुलना में "सामान्य" लगता है ...


कृपया, कृपया हमें बताएं कि ऐसा कैसे करें ("दो तिथियों के बीच कितना समय बीत गया" यह पता करें)!
एंटोन गोगोलेव

मेरी इच्छा है कि मैं एक आसान तरीका जानता हूं ... जिसमें लीप वर्ष, उछल महीने, और अस्पष्ट दिन शामिल हैं ...
एरन मेडन

1
यह भी देखें, org.apache.commons.lang.time: commons.apache.org/lang//api/org/apache/commons/lang/time/...
trashgod

@AntonGogolev में java.time , उपयोग Periodऔर Durationकक्षाएं की गणना और क्रमशः साल-महीने-दिन और घंटे-मिनट-सेकंड के पैमाने पर बीता हुआ समय प्रतिनिधित्व करते हैं।
बेसिल बॉर्कल

4

मुझे ईमानदार होने के लिए जावा की तारीख एपीआई उपयोगी लगती है। मुद्दों मैंने देखा और के बारे में सुना है के अधिकांश शब्दाडंबर, उपयोगी कुछ भी (करने के लिए कई वर्गों को शामिल करने की जरूरत से संबंधित हैं Calendar, Date, DateFormat/ SimpleDateFormat) और की तरह साधारण accessors की कमी getDayOfWeek()

Joda Time जावा में एक अच्छी तरह से सम्मानित वैकल्पिक एपीआई है, और क्यों Joda Time खंड में यह कुछ और तर्क देता है कि यह एक व्यवहार्य विकल्प क्यों है जो ब्याज का हो सकता है।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.