जावा: तारीख निर्माणकर्ता को पदावनत क्यों किया जाता है, और मैं इसके बजाय क्या उपयोग करूं?


211

मैं C # दुनिया से आता हूं, इसलिए अभी तक जावा के साथ अनुभव नहीं किया गया है। मुझे सिर्फ ग्रहण द्वारा बताया गया Dateथा जिसे हटा दिया गया था:

Person p = new Person();
p.setDateOfBirth(new Date(1985, 1, 1));

क्यों? और क्या (विशेष रूप से ऊपर जैसे मामलों में) इसके बजाय उपयोग किया जाना चाहिए?


37
मैं एक समान सीखने की अवस्था का अनुभव कर रहा हूं, यह भी C # से जावा तक जा रहा है। दूसरी बात जो मुझे बहुत परेशान करती है, वह यह है कि वर्ष का महीना एक 0-आधारित प्रणाली है (0 से 11 तक जहाँ जनवरी = 0 और दिसंबर = 11) लेकिन महीने के दिन 1-आधारित (1 से 31) हैं। उस एक पर सिर!
पॉल सासिक

2
@ पाओल शशिक, हाँ, लेकिन कैलेंडर है। उदाहरण के लिए जनेरी स्थिरांक, और प्रत्येक महीने के लिए एक
डियागो

5
@PaulSasik lol हाँ, बेवकूफ जावा। दर्द और दुख के लिए सी # से जावा और ओएमजी पर स्विच करना पड़ा।
cbmeeks


8
Snarky "lol" टिप्पणी जावा से C # के बारे में लोगों ने मुझे हंसाया क्योंकि .Net को उत्कृष्ट जावा पुस्तकालय Joda-Time के बंदरगाह से अपनी सभ्य तिथि-समय पुस्तकालय ( Noda Time ) मिला ।
तुलसी बोर्क

जवाबों:


97

विशिष्ट Dateनिर्माणकर्ता को पदावनत Calendarकिया जाता है , और इसके बजाय इसका उपयोग किया जाना चाहिए। JavaDocके लिए तिथि का वर्णन करता है जो कंस्ट्रक्टर्स पदावनत कर रहे हैं और एक का उपयोग कर उन्हें बदलने के लिए कैसे Calendar


25
कैलेंडर के लिए एक अतिरिक्त ऑब्जेक्ट की आवश्यकता होती है और उसी कार्य को करने के लिए 8 लाइनों के समान कोड की आवश्यकता होती है जो कि मैं जो बता सकता हूं उससे एक दिनांक ऑब्जेक्ट बनाता है। यह भ्रामक है और अनावश्यक लगता है जब आपको केवल एक दिनांक की आवश्यकता होती है और एक समयक्षेत्र समायोजित चर की नहीं।
G_V

5
FYI करें, इस तरह के रूप में बहुत परेशानी पुराने तिथि-समय कक्षाएं java.util.Date, java.util.Calendarऔर java.text.SimpleDateFormatअब कर रहे हैं विरासत , द्वारा का स्थान ले लिया java.time जावा 8 और बाद में बनाया गया वर्गों। ओरेकल द्वारा ट्यूटोरियल देखें ।
तुलसी बॉर्क

250

java.util.Dateवर्ग वास्तव में पदावनत नहीं है, सिर्फ इतना है कि निर्माता, कुछ अन्य निर्माताओं / तरीकों अनुचित हैं के साथ। इसे हटा दिया गया था क्योंकि इस तरह का उपयोग अंतर्राष्ट्रीयकरण के साथ अच्छी तरह से काम नहीं करता है। इसके Calendarबजाय कक्षा का उपयोग किया जाना चाहिए:

Calendar cal = Calendar.getInstance();
cal.set(Calendar.YEAR, 1988);
cal.set(Calendar.MONTH, Calendar.JANUARY);
cal.set(Calendar.DAY_OF_MONTH, 1);
Date dateRepresentation = cal.getTime();

जावदोक की तारीख पर नज़र डालें:

http://download.oracle.com/javase/6/docs/api/java/util/Date.html


2
यह सबसे अच्छा जवाब होना चाहिए। धन्यवाद।
jordaniac89

"अंतर्राष्ट्रीयकरण के साथ अच्छी तरह से काम नहीं करता" कहकर, क्या आपका मतलब है कि दिनांक के लिए, आप इसके लिए TimeZone असाइन नहीं कर सकते हैं? धन्यवाद
DiveInto

क्या दिनांक एक स्ट्रिंग को पार्स किया गया था, इसलिए अब हमें एक स्ट्रिंग को प्रतिस्थापित करना होगा जिसमें वर्ष, महीना और दिन शामिल हों? किसी चीज के लिए बहुत अधिक अतिरिक्त परेशानी की तरह लगता है जो ज्यादातर मामलों में इस तरह के जटिल तर्क और तरीकों को जोड़ने की आवश्यकता नहीं होती है।
G_V

1
बस जोड़ने के लिए, यह डिफ़ॉल्ट समयक्षेत्र को ध्यान में रखेगा। यदि हम किसी अन्य टाइमज़ोन को निर्दिष्ट करना चाहते हैं, तो हम उपयोग कर सकते हैंCalendar cal = Calendar.getInstance(TimeZone.getTimeZone(<timezone id>));
विकास प्रसाद

1
"इसके बजाय कैलेंडर क्लास का उपयोग किया जाना चाहिए" - जावा 8 और बाद के लिए, java.time.*कक्षाएं बेहतर विकल्प हैं ... यदि आप अपना कोड बदल रहे हैं।
स्टीफन सी

73

tl; डॉ

LocalDate.of( 1985 , 1 , 1 )

... या ...

LocalDate.of( 1985 , Month.JANUARY , 1 )

विवरण

java.util.Date, java.util.Calendar, और java.text.SimpleDateFormatकक्षाओं बहुत जल्दी पहुंचे जब जावा पहले शुरू किया और विकसित किया गया था। कक्षाओं को अच्छी तरह से डिज़ाइन या कार्यान्वित नहीं किया गया था। सुधारों का प्रयास किया गया था, इस प्रकार आपके द्वारा पाया गया वेतन वृद्धि। दुर्भाग्य से सुधार के प्रयास काफी हद तक विफल रहे। आपको इन वर्गों से पूरी तरह बचना चाहिए । नई कक्षाओं द्वारा उन्हें जावा 8 में दबा दिया गया है।

आपके कोड में समस्याएं

एक java.util.Date में दिनांक और समय दोनों भाग होते हैं। आपने अपने कोड में समय भाग को अनदेखा कर दिया। इसलिए दिनांक वर्ग आपके जेवीएम के डिफ़ॉल्ट समय क्षेत्र द्वारा परिभाषित दिन की शुरुआत लेगा और उस समय को दिनांक ऑब्जेक्ट पर लागू करेगा। इसलिए आपके कोड के परिणाम भिन्न होंगे कि यह किस मशीन पर चलता है या कौन सा समय क्षेत्र निर्धारित है। शायद नहीं जो आप चाहते हैं।

यदि आप समय के बिना सिर्फ तारीख चाहते हैं, जैसे जन्म तिथि, तो आप किसी Dateवस्तु का उपयोग नहीं करना चाहते हैं । आईएसओ 8601 प्रारूप में आप तारीख के एक तार को स्टोर करना चाह सकते हैं YYYY-MM-DD। या LocalDateजोडा-टाइम (नीचे देखें) से एक ऑब्जेक्ट का उपयोग करें ।

Joda समय

जावा में सीखने के लिए पहली बात: कुख्यात परेशान करने वाले java.util से बचें

जैसा कि user3277382 द्वारा उत्तर में सही ढंग से उल्लेख किया गया है , जावा 8 में या तो Joda-Time या नया java.time * पैकेज का उपयोग करें।

कोड कोड जोडा-टाइम 2.3 में

DateTimeZone timeZoneNorway = DateTimeZone.forID( "Europe/Oslo" );
DateTime birthDateTime_InNorway = new DateTime( 1985, 1, 1, 3, 2, 1, timeZoneNorway );

DateTimeZone timeZoneNewYork = DateTimeZone.forID( "America/New_York" );
DateTime birthDateTime_InNewYork = birthDateTime_InNorway.toDateTime( timeZoneNewYork ); 

DateTime birthDateTime_UtcGmt = birthDateTime_InNorway.toDateTime( DateTimeZone.UTC );

LocalDate birthDate = new LocalDate( 1985, 1, 1 );

सांत्वना दें…

System.out.println( "birthDateTime_InNorway: " + birthDateTime_InNorway );
System.out.println( "birthDateTime_InNewYork: " + birthDateTime_InNewYork );
System.out.println( "birthDateTime_UtcGmt: " + birthDateTime_UtcGmt );
System.out.println( "birthDate: " + birthDate );

जब चला…

birthDateTime_InNorway: 1985-01-01T03:02:01.000+01:00
birthDateTime_InNewYork: 1984-12-31T21:02:01.000-05:00
birthDateTime_UtcGmt: 1985-01-01T02:02:01.000Z
birthDate: 1985-01-01

java.time

इस स्थिति में java.time का कोड जोडा-टाइम के समान है ।

हमें एक टाइम ज़ोन ( ZoneId) मिलता है, और उस टाइम ज़ोन ( ZonedDateTime) को दी गई डेट-टाइम ऑब्जेक्ट का निर्माण होता है । तब का उपयोग कर अपरिवर्तनीय वस्तुओं पैटर्न, हम पुराने वस्तु की एक ही पल के आधार पर नए तिथि-समय बनाने (के बाद से नैनोसेकंड की गिनती युग लेकिन सौंपा अन्य समय क्षेत्र)। अंत में हमें एक LocalDateदिन का समय नहीं है और न ही समय क्षेत्र है, हालांकि उस समय का निर्धारण करते समय समय क्षेत्र लागू होने पर नोटिस ( उदाहरण के लिए न्यूयॉर्क में ओस्लो की तुलना में एक नया दिन पहले होता है )।

ZoneId zoneId_Norway = ZoneId.of( "Europe/Oslo" );
ZonedDateTime zdt_Norway = ZonedDateTime.of( 1985 , 1 , 1 , 3 , 2 , 1 , 0 , zoneId_Norway );

ZoneId zoneId_NewYork = ZonedId.of( "America/New_York" );
ZonedDateTime zdt_NewYork = zdt_Norway.withZoneSameInstant( zoneId_NewYork );

ZonedDateTime zdt_Utc = zdt_Norway.withZoneSameInstant( ZoneOffset.UTC );  // Or, next line is similar.
Instant instant = zdt_Norway.toInstant();  // Instant is always in UTC.

LocalDate localDate_Norway = zdt_Norway.toLocalDate();

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

Java.time ढांचे जावा 8 और बाद में बनाया गया है। इन कक्षाओं परेशानी वर्ष प्रतिस्थापित विरासत जैसे तिथि-समय कक्षाएं java.util.Date, Calendar, और SimpleDateFormat

Joda समय परियोजना, अब में रखरखाव मोड , प्रवास करने की सलाह देता java.time कक्षाएं।

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

आप अपने डेटाबेस से सीधे java.time वस्तुओं का आदान-प्रदान कर सकते हैं । JDBC 4.2 या उसके बाद के JDBC ड्राइवर का अनुपालन करें । तार की कोई जरूरत नहीं, कक्षाओं की कोई जरूरत नहीं ।java.sql.*

Java.time कक्षाएं कहाँ से प्राप्त करें?

ThreeTen-अतिरिक्त परियोजना अतिरिक्त कक्षाओं के साथ java.time फैली हुई है। यह परियोजना java.time के लिए भविष्य के अतिरिक्त के लिए एक साबित जमीन है। आप यहाँ कुछ उपयोगी वर्गों जैसे मिल सकता है Interval, YearWeek, YearQuarter, और अधिक


5
वास्तव में मूल कारण का उल्लेख करने और सभी उपलब्ध विकल्पों की कवरेज प्रदान करने के लिए सहारा।
मबी

यह सही उत्तर है और कैलेंडर वर्ग से बचना चाहिए। थ्रीटैन सबसे अच्छा विकल्प है
ant2009

11

एक कारण यह है कि निर्माणकर्ता पदावनत है, वर्ष पैरामीटर का अर्थ वह नहीं है जो आप अपेक्षा करेंगे। जावदोक कहता है:

JDK संस्करण 1.1 के रूप में, द्वारा प्रतिस्थापित किया गया Calendar.set(year + 1900, month, date)

ध्यान दें कि वर्ष क्षेत्र के बाद से वर्षों की संख्या है 1900, इसलिए आपका नमूना कोड सबसे अधिक संभावना वह नहीं करेगा जो आप इसे करने की अपेक्षा करते हैं। और यही बात है।

सामान्य तौर पर, Dateएपीआई केवल आधुनिक पश्चिमी कैलेंडर का समर्थन करता है, इसमें विशेष रूप से निर्दिष्ट घटक होते हैं, और यदि आप फ़ील्ड सेट करते हैं तो असंगत व्यवहार करते हैं।

Calendarऔर GregorianCalendarएपीआई से बेहतर हैं Date, और 3 पक्ष Joda समय एपीआई आम तौर पर सबसे अच्छा माना गया। जावा 8 में, उन्होंने java.timeपैकेज पेश किए, और ये अब अनुशंसित विकल्प हैं।


यह समाधान बहुत अच्छा काम करता है, सिवाय इसके कि यह शून्य-समय-मिनट-सेकंड-मिलीसेकंड के लिए उपयोग नहीं करता है जैसे नई तिथि (वर्ष, माह, दिन)। तो हमें कुछ इस तरह की आवश्यकता है: कैलेंडर कैल = Calendar.getInstance (); cal.clear (); cal.set (वर्ष + 1900, महीना, तारीख); तारीख तारीख़ रिप्रेंटेशन = cal.getTime ();
जोएल रिचर्ड कोएट

11

मुझे यह सवाल एक नए सवाल के डुप्लिकेट के रूप में आया, जिसमें पूछा गया था कि नॉन-डिप्रेस्ड तरीका क्या हैDate एक विशिष्ट वर्ष, महीने और दिन ।

यहाँ उत्तर अब तक Calendarकक्षा का उपयोग करने के लिए कहते हैं , और यह सच था जब तक कि जावा 8 बाहर नहीं आया था। लेकिन जावा 8 के रूप में, ऐसा करने का मानक तरीका है:

LocalDate localDate = LocalDate.of(1985, 1, 1);

और फिर अगर आपको वास्तव में इसकी आवश्यकता है java.util.Date, तो आप इस प्रश्न में सुझावों का उपयोग कर सकते हैं

अधिक जानकारी के लिए, जावा 8 के लिए एपीआई या ट्यूटोरियल देखें


7

कृपया ध्यान दें कि Calendar.getTime()इस अर्थ में nondeterministic है कि दिन का समय वर्तमान समय के लिए चूक जाता है।

पुन: उत्पन्न करने के लिए, एक-दो बार कोड का पालन करने का प्रयास करें:

Calendar c = Calendar.getInstance();
c.set(2010, 2, 7); // NB: 2 means March, not February!
System.err.println(c.getTime());

आउटपुट उदा .:

Sun Mar 07 10:46:21 CET 2010

ठीक उसी कोड को कुछ मिनट बाद चलाना पैदावार:

Sun Mar 07 10:57:51 CET 2010

इसलिए, जबकि set()संबंधित क्षेत्रों को मूल्यों को सही करने के लिए मजबूर किया जाता है, यह अन्य क्षेत्रों के लिए सिस्टम समय को लीक करता है। (सूर्य jdk6 और jdk7 के साथ ऊपर परीक्षण किया गया)



5

वर्तमान में अधिकांश जावा डेवलपर्स तीसरे पक्ष के पैकेज Joda-Time का उपयोग करते हैं । यह व्यापक रूप से एक बेहतर कार्यान्वयन माना जाता है।

Java 8 में एक नया java.time होगा। * पैकेज । इस लेख को देखें, JDK 8 के लिए नई तिथि और समय एपीआई का परिचय


2

जैसे ही डेट कंस्ट्रक्टर को पदावनत किया जाता है, आप इस कोड को आज़मा सकते हैं।

import java.util.Calendar;

  Calendar calendar = Calendar.getInstance();
     calendar.set(Calendar.HOUR_OF_DAY, 6);// for 6 hour
     calendar.set(Calendar.MINUTE, 0);// for 0 min
     calendar.set(Calendar.SECOND, 0);// for 0 sec
     calendar.set(1996,0,26);// for Date [year,month(0 to 11), date]

    Date date = new Date(calendar.getTimeInMillis());// calendar gives long value

    String mConvertedDate = date.toString();// Fri Jan 26 06:00:00 GMT+05:30 1996

1
ये भयानक कक्षाएं अब विरासत हैं, जेएसआर 310 में परिभाषित java.time कक्षाओं द्वारा वर्षों पहले दबा दिया गया है । सुझाव Dateऔर Calendar2019 में खराब सलाह है।
तुलसी बोर्क

@BasilBourque सुझाव के लिए धन्यवाद, मैं इसे जल्द ही अपडेट करने के लिए उत्सुक हूं।
दिव्यांशु कुमार


1

आप कक्षा new Date(year,month,date)का उपयोग करके अपने कोड की तरह एक विधि बना सकते हैं Calendar

private Date getDate(int year,int month,int date){
    Calendar cal = Calendar.getInstance();
    cal.set(Calendar.YEAR, year);
    cal.set(Calendar.MONTH, month-1);
    cal.set(Calendar.DAY_OF_MONTH, day);
    return cal.getTime();
}

यह उसी तरह का काम करेगा जैसा कि वंचित कंस्ट्रक्टर का है Date


1
विशेष रूप से और विशेष रूप से आधुनिक जावा वर्गों द्वारा इन भयानक परेशानियों वाले वर्गों को वर्षों पहले दबा दिया गया था । InstantZonedDateTime
बेसिल बोर्ख

ऊपर दिए गए समाधान में वर्ष को 1900 जोड़ना चाहिए, और महीने से 1 को घटाया नहीं जाना चाहिए, और कैलेंडर.गेट इंसटेंस () लाइन के बाद cal.clear () भी चलना चाहिए, ताकि घंटे / मिनट / सेकंड / मिलीसेकंड शून्य हो जाएं वे डेट कंस्ट्रक्टर में करते हैं)।
जोएल रिचर्ड कोएट

1

दिनांक निर्माणकर्ता वर्ष के प्रारूप में वर्ष 1900, शून्य-आधारित महीनों, एक-आधारित दिनों की अपेक्षा करता है, और घंटे / मिनट / सेकंड / मिलीसेकंड को शून्य पर सेट करता है।

Date result = new Date(year, month, day);

इसलिए कैलेंडर प्रतिस्थापन (शून्य-आधारित वर्ष, शून्य-आधारित महीने, एक-आधारित दिन) का उपयोग करते हुए पदावनत किए गए दिनांक निर्माता के लिए, हमें कुछ इस तरह की आवश्यकता है:

Calendar calendar = Calendar.getInstance();
calendar.clear(); // Sets hours/minutes/seconds/milliseconds to zero
calendar.set(year + 1900, month, day);
Date result = calendar.getTime();

या जावा 1.8 का उपयोग करना (जिसमें शून्य-आधारित वर्ष और एक-आधारित महीने और दिन हैं):

Date result = Date.from(LocalDate.of(year + 1900, month + 1, day).atStartOfDay(ZoneId.systemDefault()).toInstant());

यहाँ दिनांक, कैलेंडर और जावा 1.8 के बराबर संस्करण हैं:

int year = 1985; // 1985
int month = 1; // January
int day = 1; // 1st

// Original, 1900-based year, zero-based month, one-based day
Date date1 = new Date(year - 1900, month - 1, day);

// Calendar, zero-based year, zero-based month, one-based day
Calendar calendar = Calendar.getInstance();
calendar.clear(); // Sets hours/minutes/seconds/milliseconds to zero
calendar.set(year, month - 1, day);
Date date2 = calendar.getTime();

// Java-time back to Date, zero-based year, one-based month, one-based day
Date date3 = Date.from(LocalDate.of(year, month, day).atStartOfDay(ZoneId.systemDefault()).toInstant());

SimpleDateFormat format = new SimpleDateFormat("yyyy-MMM-dd HH:mm:ss.SSS");

// All 3 print "1985-Jan-01 00:00:00.000"
System.out.println(format.format(date1));
System.out.println(format.format(date2));
System.out.println(format.format(date3));

1
इन दोनों भयानक वर्गों को जेएसआर 310 में परिभाषित java.time कक्षाओं द्वारा वर्षों पहले दबा दिया गया था ।
तुलसी बॉर्क

दिनांक, कैलेंडर और जावा 1.8 संस्करण दिखाने के लिए अद्यतित उत्तर।
जोएल रिचर्ड कोएट

0
new GregorianCalendar(1985, Calendar.JANUARY, 1).getTime();

(पूर्व जावा -8 रास्ता)


यह शायद सबसे अच्छा है जो आप java.time के बिना कर सकते हैं। हालाँकि, प्री-जावा 8 भी आप java.time का उपयोग कर सकते हैं, एक बैकपोर्ट है: थ्रीटेन बैकपोर्ट लाइब्रेरी
ओले वीवी
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.