java - जावा कैलेंडर में जनवरी महीने 0 क्यों है?




calendar (14)

java.util.Calendar , जनवरी को महीने 0 के रूप में परिभाषित किया गया है, महीने 1 नहीं। क्या इसका कोई विशिष्ट कारण है?

मैंने देखा है कि बहुत से लोग इस बारे में भ्रमित हो रहे हैं ...


Answers

जावा 8 में, एक नई तिथि / समय एपीआई जेएसआर 310 है जो अधिक सनी है। स्पेस लीड जोडाटाइम के प्राथमिक लेखक के समान है और वे कई समान अवधारणाओं और पैटर्न साझा करते हैं।


निजी तौर पर, मैंने जावा कैलेंडर एपीआई की अजीबता को एक संकेत के रूप में लिया कि मुझे खुद को ग्रेगोरियन-केंद्रित मानसिकता से तलाक लेने की आवश्यकता है और उस सम्मान में अधिक अज्ञात रूप से कार्यक्रम करने की कोशिश की गई है। विशेष रूप से, मैंने महीनों की तरह चीजों के लिए हार्डकोडेड स्थिरांक से बचने के लिए एक बार फिर सीखा।

निम्नलिखित में से कौन सा सही होने की संभावना है?

if (date.getMonth() == 3) out.print("March");

if (date.getMonth() == Calendar.MARCH) out.print("March");

यह एक चीज को दर्शाता है जो मुझे जोदा समय के बारे में थोड़ा परेशान करता है - यह प्रोग्रामर को हार्डकोडेड स्थिरांक के संदर्भ में सोचने के लिए प्रोत्साहित कर सकता है। (केवल थोड़ी सी, हालांकि। ऐसा नहीं है कि जोडा प्रोग्रामर को बुरी तरह प्रोग्राम करने के लिए मजबूर कर रहा है।)


क्योंकि सब कुछ 0 से शुरू होता है। यह जावा में प्रोग्रामिंग का मूल तथ्य है। अगर एक चीज उस से विचलित हो जाती है, तो इससे भ्रम की पूरी नींद आती है। आइए उनके गठन और उनके साथ कोड का तर्क न दें।


इसके बहुत सारे जवाब हैं, लेकिन मैं वैसे भी इस विषय पर अपना विचार दूंगा। जैसा कि पहले बताया गया है, इस अजीब व्यवहार के पीछे कारण POSIX C time.h से आता है, जहां महीनों में 0-11 के साथ एक int में संग्रहीत महीनों। समझाने के लिए, इसे इस तरह देखो; वर्षों और दिन बोली जाने वाली भाषा में संख्या माना जाता है, लेकिन महीनों के अपने नाम हैं। इसलिए क्योंकि जनवरी पहला महीना है, इसे ऑफ़सेट 0, पहला सरणी तत्व के रूप में संग्रहीत किया जाएगा। monthname[JANUARY] "January" । वर्ष में पहला महीना पहला महीना सरणी तत्व है।

दूसरी तरफ दिन की संख्या, क्योंकि उनके पास नाम नहीं हैं, इसलिए उन्हें 0-30 के रूप में एक int में संग्रहीत करना भ्रमित हो जाएगा, आउटपुट के लिए बहुत सारे day+1 निर्देश जोड़ें और, ज़ाहिर है, बग्स के बहुत से प्रवण हो।

ऐसा कहा जा रहा है कि असंगतता भ्रमित है, खासकर जावास्क्रिप्ट में (जिसने इसे "फीचर" भी विरासत में मिला है), एक पटकथा भाषा जहां इसे लैंगग से बहुत दूर समझा जाना चाहिए।

टीएल; डीआर : क्योंकि महीनों में महीने के नाम और दिन नहीं होते हैं।


DannySmurf के आलस्य के जवाब के अलावा, मैं आपको जोड़ दूंगा कि यह आपको स्थिरांक का उपयोग करने के लिए प्रोत्साहित करने के लिए है, जैसे Calendar.JANUARY । जनवरी।


tl; डॉ

Month.FEBRUARY.getValue()  // February → 2.

2

विवरण

जॉन स्कीट द्वारा उत्तर सही है।

अब हमारे पास उन परेशानी पुरानी विरासत दिनांक-समय कक्षाओं के लिए आधुनिक प्रतिस्थापन है: java.time कक्षाएं।

java.time.Month

उन वर्गों में Month enum । एक enum में एक या अधिक पूर्वनिर्धारित वस्तुओं, वस्तुओं को लोड किया जाता है जो वर्ग लोड होने पर स्वचालित रूप से तत्काल होते हैं। Month हमारे पास एक दर्जन ऐसी वस्तुएं होती हैं, प्रत्येक को एक नाम दिया जाता है: JANUARY , FEBRUARY , MARCH , और इसी तरह। उनमें से प्रत्येक एक static final public वर्ग स्थिर है। आप इन ऑब्जेक्ट्स को अपने कोड में कहीं भी इस्तेमाल और पास कर सकते हैं। उदाहरण: कुछ someMethod( Month.AUGUST )

सौभाग्य से, उनके पास सौहार्द संख्या है, 1-12 जहां 1 जनवरी है और 12 दिसंबर है।

एक विशेष महीने संख्या (1-12) के लिए एक Month वस्तु प्राप्त करें।

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

साथ ही, आपको केवल पूर्णांक संख्याओं के बजाय अपने कोड बेस के आस-पास इस enum की ऑब्जेक्ट्स को पास करना चाहिए। ऐसा करने से टाइप-सुरक्षा प्रदान होती है, मानों की वैध सीमा सुनिश्चित होती है, और आपके कोड को अधिक आत्म-दस्तावेज बनाता है। जावा में आश्चर्यजनक रूप से शक्तिशाली एनम सुविधा से अपरिचित होने पर ओरेकल ट्यूटोरियल देखें।

आपको Year और YearMonth कक्षा कक्षा भी उपयोगी मिल सकती है।

जावा के बारे में

java.time फ्रेमवर्क जावा 8 और बाद में बनाया गया है। ये कक्षाएं परेशानी पुरानी legacy दिनांक-समय कक्षाओं जैसे java.util.Date , .Calendar , और java.text.SimpleDateFormat

Joda-Time प्रोजेक्ट, अब रखरखाव मोड में , जावा.टाइम में माइग्रेशन की सलाह देता है।

अधिक जानने के लिए, ओरेकल ट्यूटोरियल देखें। और कई उदाहरणों और स्पष्टीकरणों के लिए स्टैक ओवरफ़्लो खोजें। विशिष्टता जेएसआर 310 है

जावा.टाइम कक्षाएं कहां प्राप्त करें?

  • जावा एसई 8 और एसई 9 और बाद में
    • निर्मित।
    • एक बंडल कार्यान्वयन के साथ मानक जावा एपीआई का हिस्सा।
    • जावा 9 कुछ मामूली विशेषताओं और फिक्सेस जोड़ता है।
  • जावा एसई 6 और एसई 7
    • जावाटाइम की अधिकांश कार्यक्षमता को ThreeTen-Backport में जावा 6 और 7 में बैक-पोर्ट किया गया है।
  • Android
    • ThreeTenABP प्रोजेक्ट विशेष रूप से एंड्रॉइड के लिए थ्रीटेन-बैकपोर्ट (ऊपर उल्लिखित) को अनुकूलित करता है।
    • देखें कि कैसे उपयोग करें ...।

ThreeTen-Extra प्रोजेक्ट अतिरिक्त कक्षाओं के साथ जावा.टाइम बढ़ाता है। यह परियोजना java.time के संभावित भविष्य के जोड़ों के लिए एक सिद्ध भूमि है। आपको यहां कुछ उपयोगी कक्षाएं मिल सकती हैं जैसे Interval , YearWeek , YearQuarter , more


क्योंकि महीनों के साथ गणित करना बहुत आसान है।

दिसम्बर के बाद 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

सभी महीने एक ही काम करते हैं और चारों ओर एक काम जरूरी नहीं है।


यह भयानक गड़बड़ी का हिस्सा है जो जावा तिथि / समय एपीआई है। इसमें जो भी गलत है, उसे सूचीबद्ध करना बहुत लंबा समय लगेगा (और मुझे यकीन है कि मुझे समस्याओं का आधा पता नहीं है)। तारीखों और समय के साथ स्वीकार्य रूप से काम करना मुश्किल है, लेकिन वैसे भी aaargh।

अपने आप को एक पक्ष बनाओ और इसके बजाय जोडा समय का उपयोग करें, या संभवतः JSR-310

संपादित करें: कारणों के लिए - जैसा कि अन्य उत्तरों में उल्लेख किया गया है, यह पुराने सी एपीआई के कारण हो सकता है, या 0 से सबकुछ शुरू करने की सामान्य भावना हो सकती है ... सिवाय इसके कि दिन 1 से शुरू होते हैं। मुझे संदेह है कि मूल कार्यान्वयन टीम के बाहर कोई भी वास्तव में कारण बता सकता है - लेकिन फिर से, मैं पाठकों से आग्रह करता हूं कि क्यों बुरा निर्णय नहीं लिया गया, ताकि java.util.Calendar में java.util.Calendar के पूरे मैदान को देखने के लिए। 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 महीनों के साथ कैलेंडर प्राप्त होने पर ही विफल हो जाता है ... लेकिन कम से कम निर्दिष्ट आकार आपके द्वारा अपेक्षित महीनों की संख्या है।

यह एक अच्छा कारण नहीं है, लेकिन यह एक कारण है ...

संपादित करें: एक टिप्पणी के प्रकार के बारे में कुछ विचारों के बारे में कुछ विचार जो मुझे लगता है तिथि / कैलेंडर के साथ गलत है:

  • आश्चर्यजनक आधार (दिनांक में वर्ष आधार के रूप में 1 9 00, स्वीकार्य रूप से बहिष्कृत रचनाकारों के लिए; 0 दोनों में आधार आधार के रूप में)
  • उत्परिवर्तन - अपरिवर्तनीय प्रकारों का उपयोग करना वास्तव में प्रभावी रूप से मूल्यवान कार्यों के साथ काम करना बहुत आसान बनाता है
  • प्रकारों का एक अपर्याप्त सेट: अलग-अलग चीजों के रूप में Date और Calendar होना अच्छा लगता है, लेकिन "स्थानीय" बनाम "ज़ोन" मानों को अलग करना, दिनांक / समय बनाम दिनांक बनाम समय है
  • एक एपीआई जो स्पष्ट रूप से नामित तरीकों के बजाय, जादू स्थिरांक के साथ बदसूरत कोड की ओर जाता है
  • एक एपीआई जो कि कारणों के बारे में तर्क करना बहुत मुश्किल है - चीजों को फिर से तैयार करने के बारे में सभी व्यवसाय आदि
  • "अब" के लिए डिफ़ॉल्ट रूप से पैरामीटर रहित कन्स्ट्रक्टर का उपयोग, जो हार्ड-टू-टेस्ट कोड की ओर जाता है
  • Date.toString() कार्यान्वयन जो हमेशा सिस्टम स्थानीय समय क्षेत्र का उपयोग करता है (जो अब पहले कई स्टैक ओवरफ़्लो उपयोगकर्ताओं को भ्रमित कर रहा है)

इसे बिल्कुल शून्य के रूप में परिभाषित नहीं किया गया है, इसे कैलेंडर के रूप में परिभाषित किया गया है। जनवरी। यह इंटम्स के बजाय स्थिरांक के रूप में इन्स का उपयोग करने की समस्या है। कैलेंडर। जनवरी == 0।


क्योंकि प्रोग्रामर 0-आधारित इंडेक्स से ग्रस्त हैं। ठीक है, यह उससे थोड़ा अधिक जटिल है: जब आप निम्न-स्तरीय तर्क के साथ 0-आधारित अनुक्रमण का उपयोग करने के लिए काम कर रहे हैं तो यह अधिक समझ में आता है। लेकिन बड़े पैमाने पर, मैं अभी भी अपनी पहली वाक्य के साथ रहूंगा।


सी आधारित भाषाओं को सी डिग्री कुछ डिग्री। tm संरचना ( time.h में परिभाषित) में एक पूर्णांक फ़ील्ड tm_mon जिसमें 0-11 की (टिप्पणी की गई) सीमा है।

सी आधारित भाषाएं इंडेक्स 0 पर सरणी शुरू करती हैं। इसलिए यह इंडेक्स के रूप में tm_mon साथ महीने के नामों की एक सरणी में स्ट्रिंग को आउटपुट करने के लिए सुविधाजनक था।


मेरे लिए, कोई भी mindpro.com से बेहतर नहीं बताता है:

gotchas

java.util.GregorianCalendar में old java.util.Date क्लास की तुलना में बहुत कम कीड़े और गॉथस हैं लेकिन यह अभी भी कोई पिकनिक नहीं है।

जब डेलाइट सेविंग टाइम का पहला प्रस्ताव दिया गया था तो प्रोग्रामर रहे थे, तो वे इसे पागल और अव्यवस्थित के रूप में विचलित कर देते थे। डेलाइट सेविंग के साथ, एक मौलिक अस्पष्टता है। गिरावट में जब आप अपने घड़ियों को 2 बजे एक घंटे वापस सेट करते हैं तो समय में दो अलग-अलग इंस्टेंट होते हैं जिन्हें स्थानीय समय 1:30 पूर्वाह्न कहा जाता है। आप उन्हें केवल तभी बता सकते हैं जब आप रिकॉर्ड करते हैं कि क्या आप डेलाइट सेविंग या रीडिंग के साथ मानक समय का इरादा रखते हैं।

दुर्भाग्य से, GregorianCalendar को बताने का कोई तरीका नहीं है जिसका आप इरादा रखते हैं। आपको अस्पष्टता से बचने के लिए डमी यूटीसी टाइमज़ोन के साथ स्थानीय समय बताने का सहारा लेना चाहिए। प्रोग्रामर आमतौर पर इस समस्या पर अपनी आंखें बंद करते हैं और उम्मीद करते हैं कि इस घड़ी के दौरान कोई भी कुछ भी नहीं करता है।

मिलेनियम बग। बग अभी भी कैलेंडर कक्षाओं से बाहर नहीं हैं। यहां तक ​​कि जेडीके (जावा डेवलपमेंट किट) 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 */

एमएसटी के लिए 2001/01/01 को 7 बजे बग गायब हो गया।

GregorianCalendar को अनियंत्रित int जादू स्थिरांक के ढेर के विशालकाय द्वारा नियंत्रित किया जाता है। यह तकनीक पूरी तरह से संकलन-समय त्रुटि जांच की किसी भी आशा को नष्ट कर देती है। उदाहरण के लिए आप GregorianCalendar. get(Calendar.MONTH)); उपयोग करने के महीने प्राप्त करने के लिए GregorianCalendar. get(Calendar.MONTH)); GregorianCalendar. get(Calendar.MONTH));

GregorianCalendar GregorianCalendar.get(Calendar.ZONE_OFFSET) में कच्चे GregorianCalendar.get(Calendar.ZONE_OFFSET) और डेलाइट बचत GregorianCalendar. get( Calendar. DST_OFFSET) GregorianCalendar. get( Calendar. DST_OFFSET) , लेकिन वास्तविक समय क्षेत्र ऑफ़सेट का उपयोग करने का कोई तरीका नहीं है। आपको इन दोनों को अलग से प्राप्त करना होगा और उन्हें एक साथ जोड़ना होगा।

GregorianCalendar.set( year, month, day, hour, minute) सेकंड को 0 पर सेट नहीं करता है।

DateFormat और GregorianCalendar सही ढंग से जाल नहीं करते हैं। एक बार अप्रत्यक्ष रूप से तिथि के रूप में, आपको दो बार कैलेंडर निर्दिष्ट करना होगा।

यदि उपयोगकर्ता ने अपना समय क्षेत्र सही तरीके से कॉन्फ़िगर नहीं किया है तो यह चुपचाप पीएसटी या जीएमटी के लिए डिफ़ॉल्ट रूप से डिफ़ॉल्ट होगा।

ग्रेगोरियन कैलेंडर में, महीनों की संख्या जनवरी = 0 से शुरू होती है, 1 की बजाय 1 ग्रह के हर किसी के रूप में। फिर भी दिन 1 सप्ताह से शुरू होता है जैसे रविवार = 1, सोमवार = 2, ... शनिवार = 7। फिर भी डेटफॉर्मेट। पार्स जनवरी = 1 के साथ पारंपरिक तरीके से व्यवहार करता है।


java.util.Month

जावा आपको महीनों के लिए 1 आधारित इंडेक्स का उपयोग करने का एक और तरीका प्रदान करता है। java.time.Month enum का प्रयोग करें। एक वस्तु बारह महीनों में से प्रत्येक के लिए पूर्वनिर्धारित है। जनवरी-दिसंबर के लिए उनके पास प्रत्येक 1-12 को आवंटित संख्याएं हैं; नंबर के लिए कॉल प्राप्त करें।

Calendar.JULY बजाय Month.JULY उपयोग करें। Month.JULY (आपको 7 देता है)। Month.JULY (आपको 6 देता है)।

(import java.time.*;)

मैंने एक्सेलिप बनाम नेटबीन्स 8.0.2 पर परीक्षण किया, दोनों जावा संस्करण 1.8 के साथ; मैंने माप के लिए System.nanoTime() उपयोग किया।

ग्रहण:

मुझे दोनों मामलों में एक ही समय मिला - लगभग 1.564 सेकंड

NetBeans:

  • "#" का प्रयोग करना: 1.536 सेकेंड
  • "बी" का प्रयोग: 44.164 सेकेंड

तो, ऐसा लगता है कि नेटबीन के प्रिंट पर कंसोल पर खराब प्रदर्शन है।

अधिक शोध के बाद मुझे एहसास हुआ कि समस्या Netbeans के अधिकतम बफर की line-wrapping है (यह System.out.println कमांड तक सीमित नहीं है), इस कोड द्वारा प्रदर्शित:

for (int i = 0; i < 1000; i++) {
    long t1 = System.nanoTime();
    System.out.print("BBB......BBB"); \\<-contain 1000 "B"
    long t2 = System.nanoTime();
    System.out.println(t2-t1);
    System.out.println("");
}

समय के परिणाम हर पांचवें पुनरावृत्ति को छोड़कर प्रत्येक पुनरावृत्ति के बाद 1 मिलीसेकंड कम होते हैं, जब समय का परिणाम लगभग 225 मिलीसेकंड होता है। कुछ ऐसा (नैनोसेकंड में):

BBB...31744
BBB...31744
BBB...31744
BBB...31744
BBB...226365807
BBB...31744
BBB...31744
BBB...31744
BBB...31744
BBB...226365807
.
.
.

और इसी तरह..

सारांश:

  1. ग्रहण पूरी तरह से "बी" के साथ काम करता है
  2. नेटबीन्स में एक लाइन-रैपिंग समस्या होती है जिसे हल किया जा सकता है (क्योंकि समस्या ग्रहण में नहीं होती है) (बी ("बी") के बाद जगह जोड़ने के बिना)।




java calendar