java.util.Calendar
जनवरी में , महीने को 0 के रूप में परिभाषित किया गया है, महीने में नहीं 1. क्या इसका कोई विशेष कारण है?
मैंने कई लोगों को इस बारे में भ्रमित होते देखा है ...
java.util.Calendar
जनवरी में , महीने को 0 के रूप में परिभाषित किया गया है, महीने में नहीं 1. क्या इसका कोई विशेष कारण है?
मैंने कई लोगों को इस बारे में भ्रमित होते देखा है ...
जवाबों:
यह भयावह गंदगी का सिर्फ एक हिस्सा है जो जावा तिथि / समय एपीआई है। यह सूचीबद्ध करना कि इसमें क्या गलत है, बहुत लंबा समय लगेगा (और मुझे यकीन है कि मुझे आधी समस्याएं नहीं पता हैं)। निश्चित रूप से तारीखों और समय के साथ काम करना मुश्किल है, लेकिन वैसे भी अनगर।
अपने आप को एक एहसान करो और बजाय Joda समय का उपयोग करें, या संभवतः JSR-310 ।
संपादित करें: जैसे कि क्यों - जैसे अन्य उत्तरों में उल्लेख किया गया है, यह अच्छी तरह से पुराने सी एपीआई के कारण हो सकता है, या केवल 0 से सब कुछ शुरू करने की एक सामान्य भावना ... सिवाय इसके कि दिन 1 से शुरू होते हैं, बिल्कुल। मुझे संदेह है कि क्या मूल कार्यान्वयन टीम के बाहर कोई भी व्यक्ति वास्तव में राज्य के कारणों को बता सकता है - लेकिन फिर, मैं पाठकों से आग्रह करूंगा कि वे इस बात की चिंता न करें कि बुरे फैसले क्यों लिए गए, जैसा कि पूरी गंभीरता से देखने के लिए java.util.Calendar
और कुछ बेहतर पाने के लिए।
एक बात जो है 0-आधारित अनुक्रमणिका का उपयोग कर के पक्ष में है कि यह "नामों में से सरणियों" जैसी चीजों बनाता है आसान है:
// I "know" there are 12 months
String[] monthNames = new String[12]; // and populate...
String name = monthNames[calendar.get(Calendar.MONTH)];
बेशक, यह विफल हो जाता है जैसे ही आप 13 महीनों के साथ एक कैलेंडर प्राप्त करते हैं ... लेकिन कम से कम निर्दिष्ट आकार आपके द्वारा अपेक्षित महीनों की संख्या है।
यह एक अच्छा कारण नहीं है , लेकिन यह एक कारण है ...
संपादित करें: एक टिप्पणी के रूप में अनुरोधों के बारे में कुछ विचार जो मुझे लगता है कि तारीख / कैलेंडर के साथ गलत है:
Date
और Calendar
अलग-अलग चीजों के रूप में है, लेकिन "स्थानीय" बनाम "ज़ोनड" मूल्यों का अलगाव गायब है, जैसा कि तारीख / समय बनाम तारीख बनाम समय हैDate.toString()
कार्यान्वयन जो हमेशा प्रणाली स्थानीय समय क्षेत्र का उपयोग करता है (कि कई स्टैक ओवरफ़्लो उपयोगकर्ताओं से पहले अब उलझन में)क्योंकि महीनों के साथ गणित करना ज्यादा आसान है।
दिसंबर के बाद 1 महीने जनवरी है, लेकिन यह पता लगाने के लिए सामान्य रूप से आपको महीने की संख्या लेनी होगी और गणित करना होगा
12 + 1 = 13 // What month is 13?
मुझे पता है! मैं 12 के मापांक का उपयोग करके इसे जल्दी से ठीक कर सकता हूं।
(12 + 1) % 12 = 1
यह नवंबर तक 11 महीने के लिए ठीक काम करता है ...
(11 + 1) % 12 = 0 // What month is 0?
आप महीने जोड़ने से पहले 1 को घटाकर फिर से इस काम के सभी बना सकते हैं, फिर अपने मापांक कर सकते हैं और अंत में फिर से 1 जोड़ सकते हैं ... उर्फ एक अंतर्निहित समस्या के आसपास काम करते हैं।
((11 - 1 + 1) % 12) + 1 = 12 // Lots of magical numbers!
अब चलो 0 - 11 महीने के साथ समस्या के बारे में सोचते हैं।
(0 + 1) % 12 = 1 // February
(1 + 1) % 12 = 2 // March
(2 + 1) % 12 = 3 // April
(3 + 1) % 12 = 4 // May
(4 + 1) % 12 = 5 // June
(5 + 1) % 12 = 6 // July
(6 + 1) % 12 = 7 // August
(7 + 1) % 12 = 8 // September
(8 + 1) % 12 = 9 // October
(9 + 1) % 12 = 10 // November
(10 + 1) % 12 = 11 // December
(11 + 1) % 12 = 0 // January
सभी महीने समान होते हैं और आस-पास का काम आवश्यक नहीं होता है।
((11 - 1 + 1) % 12) + 1 = 12
सिर्फ (11 % 12) + 1
1. महीनों के लिए यानी आपको मॉडुलो करने के बाद सिर्फ 1 जोड़ना होगा । कोई जादू की आवश्यकता है।
C आधारित भाषाएँ कुछ हद तक C की प्रतिलिपि बनाती हैं। tm
संरचना (में परिभाषित time.h
) एक पूर्णांक क्षेत्र है tm_mon
(टिप्पणी की) 0-11 की सीमा के साथ।
C आधारित भाषाएँ अनुक्रमणिका 0. पर सरणियाँ शुरू करती हैं, इसलिए यह महीने के नामों की एक स्ट्रिंग में tm_mon
अनुक्रमणिका के रूप में आउटपुट के लिए सुविधाजनक था ।
इस पर बहुत सारे उत्तर दिए गए हैं, लेकिन मैं किसी भी विषय पर अपना विचार दूंगा। इस अजीब व्यवहार के पीछे का कारण, जैसा कि पहले कहा गया था, पोसिक्स सी से आता है time.h
जहां 0-11 रेंज के साथ एक महीने में संग्रहीत किया जाता है। समझाने के लिए क्यों, इसे इस तरह से देखें; वर्षों और दिनों को बोली जाने वाली भाषा में संख्या माना जाता है, लेकिन महीनों के अपने नाम होते हैं। इसलिए क्योंकि जनवरी पहला महीना है, इसे ऑफसेट 0, पहले सरणी तत्व के रूप में संग्रहीत किया जाएगा। monthname[JANUARY]
होगा "January"
। वर्ष में पहला महीना पहले महीने का तत्व है।
दूसरी ओर दिन की संख्या, क्योंकि उनके नाम नहीं हैं, उन्हें 0-30 के रूप में एक इंट में स्टोर करना भ्रमित करने वाला होगा, day+1
आउटपुट के लिए बहुत सारे निर्देश जोड़ें और, ज़ाहिर है, बगों की एक बहुत संभावना है।
कहा जा रहा है, विसंगति भ्रामक है, विशेष रूप से जावास्क्रिप्ट में (जिसे यह "सुविधा" भी विरासत में मिली है), एक स्क्रिप्टिंग भाषा जहां यह लैंगैग से बहुत दूर अमूर्त होना चाहिए।
टीएल; डीआर : क्योंकि महीनों के नाम और महीने के दिन नहीं होते हैं।
जावा 8 में, एक नया दिनांक / समय एपीआई जेएसआर 310 है जो अधिक समझदार है। अटकल की लीड, JodaTime के प्राथमिक लेखक के समान है और वे कई समान अवधारणाओं और पैटर्नों को साझा करते हैं।
मैं कहूंगा आलस्य। एरर्स 0 से शुरू होता है (हर कोई जानता है कि); वर्ष के महीने एक सरणी है, जो मुझे विश्वास दिलाता है कि सूर्य में कुछ इंजीनियर सिर्फ जावा कोड में इस एक छोटी सी बारीकियों को डालने के लिए परेशान नहीं थे।
शायद इसलिए कि सी का "स्ट्रक्चर टीएम" वही करता है।
क्योंकि प्रोग्रामर 0-आधारित इंडेक्स से ग्रस्त हैं। ठीक है, यह उससे थोड़ा अधिक जटिल है: जब आप 0-आधारित अनुक्रमणिका का उपयोग करने के लिए निचले स्तर के तर्क के साथ काम कर रहे हैं तो यह अधिक समझ में आता है। लेकिन बड़े और, मैं अभी भी अपने पहले वाक्य के साथ रहना चाहता हूँ।
व्यक्तिगत रूप से, मैंने जावा कैलेंडर एपीआई की विचित्रता को एक संकेत के रूप में लिया कि मुझे ग्रेगोरियन-केंद्रित मानसिकता से खुद को तलाक देने की जरूरत है और उस संबंध में अधिक अज्ञेय कार्यक्रम करने की कोशिश करें। विशेष रूप से, मैंने महीनों जैसी चीजों के लिए हार्डकोडेड कॉन्स्टेंट से बचने के लिए एक बार फिर से सीखा।
निम्नलिखित में से कौन सा सही होने की अधिक संभावना है?
if (date.getMonth() == 3) out.print("March");
if (date.getMonth() == Calendar.MARCH) out.print("March");
इससे मुझे एक बात याद आती है कि जोडा टाइम के बारे में मुझे बहुत परेशान करता है - यह प्रोग्रामर को हार्डकोडेड कॉन्स्टेंट के संदर्भ में सोचने के लिए प्रोत्साहित कर सकता है। (केवल थोड़ा, हालांकि। ऐसा नहीं है कि जोडा प्रोग्रामर्स को बुरी तरह से प्रोग्राम करने के लिए मजबूर कर रहा है।)
मेरे लिए, कोई भी इसे mindpro.com से बेहतर नहीं बताता है :
gotchas
java.util.GregorianCalendar
old java.util.Date
कक्षा की तुलना में बहुत कम बग और गोच हैं, लेकिन यह अभी भी पिकनिक नहीं है।अगर डेलाइट सेविंग टाइम पहली बार प्रस्तावित किया गया था, तो वे प्रोग्रामर थे, उन्होंने इसे पागल और अडिग के रूप में वीटो किया होगा। दिन के उजाले की बचत के साथ, एक मौलिक अस्पष्टता है। गिरावट में जब आप अपनी घड़ियां एक घंटे पहले 2 बजे सेट करते हैं तो समय में दो अलग-अलग उदाहरण होते हैं, दोनों को स्थानीय समय 1:30 AM कहा जाता है। आप उन्हें केवल तभी बता सकते हैं जब आप रिकॉर्ड करते हैं कि क्या आपने डेलाइट सेविंग का इरादा किया है या रीडिंग के साथ मानक समय।
दुर्भाग्य से, यह बताने का कोई तरीका नहीं है कि
GregorianCalendar
आपने क्या इरादा किया है। अस्पष्टता से बचने के लिए आपको इसे डमी यूटीसी टाइमजोन के साथ स्थानीय समय बताने का सहारा लेना चाहिए। प्रोग्रामर आमतौर पर इस समस्या के लिए अपनी आँखें बंद कर लेते हैं और बस आशा करते हैं कि कोई भी इस घंटे के दौरान कुछ भी न करे।मिलेनियम बग। बग अभी भी कैलेंडर कक्षाओं से बाहर नहीं हैं। यहां तक कि JDK (जावा डेवलपमेंट किट) 1.3 में 2001 बग है। निम्नलिखित कोड पर विचार करें:
GregorianCalendar gc = new GregorianCalendar(); gc.setLenient( false ); /* Bug only manifests if lenient set false */ gc.set( 2001, 1, 1, 1, 0, 0 ); int year = gc.get ( Calendar.YEAR ); /* throws exception */
MST के लिए 2001/01/01 पर बग 7AM पर गायब हो जाता है।
GregorianCalendar
अनियंत्रित अंतर जादू स्थिरांक के ढेर की एक विशाल द्वारा नियंत्रित किया जाता है। यह तकनीक संकलन-समय त्रुटि जाँच की किसी भी आशा को पूरी तरह से नष्ट कर देती है। उदाहरण के लिए जिस महीने का आप उपयोग करते हैंGregorianCalendar. get(Calendar.MONTH));
GregorianCalendar
कच्चेGregorianCalendar.get(Calendar.ZONE_OFFSET)
और दिन के उजाले की बचत हैGregorianCalendar. get( Calendar. DST_OFFSET)
, लेकिन वास्तविक समय क्षेत्र का उपयोग करने के लिए कोई उपाय नहीं है। आपको इन दोनों को अलग-अलग प्राप्त करना चाहिए और उन्हें एक साथ जोड़ना होगा।
GregorianCalendar.set( year, month, day, hour, minute)
सेकंड को 0 पर सेट नहीं करता है।
DateFormat
औरGregorianCalendar
ठीक से नहीं जाल। आपको कैलेंडर को दो बार निर्दिष्ट करना होगा, एक बार अप्रत्यक्ष रूप से एक तिथि के रूप में।यदि उपयोगकर्ता ने अपने समय क्षेत्र को सही ढंग से कॉन्फ़िगर नहीं किया है, तो यह पीएसटी या जीएमटी या तो चुपचाप डिफ़ॉल्ट हो जाएगा।
ग्रेगोरियन कैलेन्डर में, महीने 1 जनवरी से शुरू होते हैं, न कि 1 जैसा कि ग्रह पर हर कोई करता है। फिर भी दिन 1 से शुरू होते हैं, सप्ताह के दिनों को रविवार = 1, सोमवार = 2,… शनिवार = 7 से शुरू करते हैं। फिर भी DateFormat। पारस जनवरी = 1 के साथ पारंपरिक तरीके से व्यवहार करता है।
java.util.Month
जावा आपको महीनों के लिए 1 आधारित अनुक्रमित का उपयोग करने का एक और तरीका प्रदान करता है। java.time.Month
एनम का उपयोग करें । प्रत्येक वस्तु बारह महीनों में से प्रत्येक के लिए पूर्वनिर्धारित होती है। उनके पास जनवरी-दिसंबर के लिए प्रत्येक 1-12 को सौंपी गई संख्या है; getValue
नंबर के लिए कॉल करें ।
का उपयोग करें Month.JULY
(आपको देता है 7) के बजाय Calendar.JULY
(आपको देता है 6)।
(import java.time.*;)
Month.FEBRUARY.getValue() // February → 2.
2
जॉन स्कीट द्वारा उत्तर सही है।
अब हमारे पास उन पुरानी पुरानी विरासत तिथि-समय वर्गों के लिए एक आधुनिक प्रतिस्थापन है: java.time कक्षाएं।
java.time.Month
उन वर्गों में से एक है एनम । एक एनुम एक या अधिक पूर्वनिर्धारित वस्तुओं को ले जाता है, ऐसी वस्तुएं जो कक्षा में लोड होने पर तुरंत स्वचालित हो जाती हैं। पर : हम एक दर्जन से अधिक इस तरह की वस्तुओं की है, प्रत्येक एक नाम दिया , , , और इतने पर। उनमें से प्रत्येक एक वर्ग स्थिर है। आप इन वस्तुओं को अपने कोड में कहीं भी उपयोग और पास कर सकते हैं। उदाहरण:Month
Month
JANUARY
FEBRUARY
MARCH
static final public
someMethod( Month.AUGUST )
सौभाग्य से, उनके पास नंबरिंग है, 1-12 जहां 1 जनवरी है और 12 दिसंबर है।
Month
किसी विशेष महीने की संख्या (1-12) के लिए एक वस्तु प्राप्त करें ।
Month month = Month.of( 2 ); // 2 → February.
दूसरी दिशा में जा रहे हैं, Month
इसके महीने की संख्या के लिए एक वस्तु पूछें ।
int monthNumber = Month.FEBRUARY.getValue(); // February → 2.
इस वर्ग पर कई अन्य आसान तरीके, जैसे कि प्रत्येक महीने में दिनों की संख्या जानना । वर्ग महीने का स्थानीयकृत नाम भी उत्पन्न कर सकता है ।
आप महीने का स्थानीय नाम विभिन्न लंबाई या संक्षिप्त में प्राप्त कर सकते हैं।
String output =
Month.FEBRUARY.getDisplayName(
TextStyle.FULL ,
Locale.CANADA_FRENCH
);
Fevrier
इसके अलावा, आपको अपने पूर्णांक संख्या के बजाय इस एनम की वस्तुओं को केवल पूर्णांक संख्याओं के साथ पास करना चाहिए । ऐसा करने से टाइप-सेफ्टी मिलती है, वैल्यू की एक वैध श्रेणी सुनिश्चित होती है, और आपके कोड को और अधिक सेल्फ-डॉक्यूमेंटिंग बनाया जाता है। जावा में आश्चर्यजनक रूप से शक्तिशाली एनम सुविधा से अपरिचित होने पर ओरेकल ट्यूटोरियल देखें ।
आपको उपयोगी Year
और YearMonth
कक्षाएं भी मिल सकती हैं ।
Java.time ढांचे जावा 8 और बाद में बनाया गया है। इन कक्षाओं परेशानी वर्ष प्रतिस्थापित विरासत जैसे तिथि-समय कक्षाएं java.util.Date
, .Calendar
, और java.text.SimpleDateFormat
।
Joda समय परियोजना, अब में रखरखाव मोड , प्रवास java.time को सलाह देता है।
अधिक जानने के लिए, Oracle ट्यूटोरियल देखें । और कई उदाहरणों और स्पष्टीकरणों के लिए ढेर अतिप्रवाह खोजें। विशिष्टता JSR 310 है ।
Java.time कक्षाएं कहाँ से प्राप्त करें?
ThreeTen-अतिरिक्त परियोजना अतिरिक्त कक्षाओं के साथ java.time फैली हुई है। यह परियोजना java.time के लिए भविष्य के अतिरिक्त के लिए एक साबित जमीन है। आप यहाँ कुछ उपयोगी वर्गों जैसे मिल सकता है Interval
, YearWeek
, YearQuarter
, और अधिक ।
इसे बिल्कुल शून्य प्रति सेगमेंट के रूप में परिभाषित नहीं किया गया है, इसे कैलेंडर के रूप में परिभाषित किया गया है। यह एनम के बजाय कॉन्स्टेंट के रूप में ints का उपयोग करने की समस्या है। कैलेन्डर.जनवरी == ०।
क्योंकि भाषा लेखन जितना दिखता है उससे अधिक कठिन है, और विशेष रूप से समय को संभालना ज्यादातर लोगों के विचार से बहुत कठिन है। समस्या के एक छोटे से हिस्से के लिए (वास्तव में, जावा नहीं), https://www.youtube.com/watch?v=-5wpm-gesOY पर YouTube वीडियो "टाइम एंड टाइमज़ोन के साथ समस्या - कंप्यूटरफाइल" देखें । यदि आपका सिर भ्रम में हँसने से गिर जाए तो आश्चर्यचकित न हों।
DannySmurf के आलस के जवाब के अलावा, मैं जोड़ूंगा कि यह आपको स्थिरांक का उपयोग करने के लिए प्रोत्साहित करेगा Calendar.JANUARY
।
क्योंकि सब कुछ 0. से शुरू होता है। यह जावा में प्रोग्रामिंग का एक मूल तथ्य है। अगर एक चीज उससे भटकती है, तो इससे भ्रम की स्थिति पैदा हो जाएगी। आइए उनके गठन और उनके साथ कोड पर बहस न करें।