ZonedDateTime को दिनांक में कैसे बदलें?


103

मैं अपने डेटाबेस में सर्वर अज्ञेय तिथि समय निर्धारित करने की कोशिश कर रहा हूं और मेरा मानना ​​है कि ऐसा करने के लिए सबसे अच्छा अभ्यास एक यूटीसी डेटाइम सेट करना है। मेरा डीबी सर्वर कैसंड्रा है और जावा के लिए डीबी ड्राइवर केवल दिनांक प्रकार को समझता है।

इसलिए यह मानते हुए कि मेरे कोड में मैं अब यूटीसी ( ZonedDateTime.now(ZoneOffset.UTC)) पाने के लिए नए जावा 8 ज़ोनडेडटेट टाइम का उपयोग कर रहा हूं ( ), मैं इस ज़ोनडेटटाइम उदाहरण को "विरासत" तिथि वर्ग में कैसे बदल सकता हूं?


जावा में निर्मित दो "तिथि" कक्षाएं हैं, java.util.Dateऔर java.sql.Date
बेसिल बॉर्क

जवाबों:


163

आप ZonedDateTime को तत्काल में परिवर्तित कर सकते हैं, जिसे आप सीधे Date के साथ उपयोग कर सकते हैं।

Date.from(java.time.ZonedDateTime.now().toInstant());

27
नहीं, यह आपके ज़ोन सिस्टम डिफ़ॉल्ट पर वर्तमान दिनांक होगा।
स्लिम सोल्टानी Dridi

6
@MilenKovachev आपके प्रश्न का कोई मतलब नहीं है - किसी दिनांक में समय क्षेत्र नहीं है - यह केवल समय में एक पल का प्रतिनिधित्व करता है।
assylias

1
@assylias वास्तव में, आपके कथन का कोई मतलब नहीं है। वह प्रारूप जिसमें समय संग्रहित होता है, एक टाइमज़ोन का अर्थ है। दिनांक UTC पर आधारित है, दुर्भाग्य से, जावा कुछ बेवकूफ चीजें करता है और इसे इस तरह से व्यवहार नहीं करता है, और इसके शीर्ष पर, UTC के बजाय स्थानीय TZ होने का समय मानता है। जिस तरह से Data, LocalDateTime, ZonedDateTime स्टोर डेटा का तात्पर्य एक समयक्षेत्र है। जिस तरह से उनका उपयोग किया जाता है वह ऐसा है जैसे कि टीबी मौजूद नहीं है, जो कि बस गलत है। java.util.Date में JVM डिफ़ॉल्ट रूप से, स्पष्ट रूप से एक TZ है। तथ्य यह है कि लोग इसे कुछ भी अलग मानते हैं (इसके लिए जावा डॉक्स सहित!) सिर्फ बुरे लोग हैं।
डेविड

5
@ दाविद उह नहीं - एक Dateयुग के बाद से कई मिलीसेकंड है - इसलिए यह यूटीसी से संबंधित है। यदि आप इसे प्रिंट करते हैं, तो डिफ़ॉल्ट टाइमज़ोन का उपयोग किया जाएगा, लेकिन दिनांक वर्ग को उपयोगकर्ता के टाइमज़ोन का कोई ज्ञान नहीं है ... उदाहरण के लिए डॉक्स में "मैपिंग" अनुभाग देखें। http://www.acle/javase/tutorial/datetime/iso-legacy .html और लोकल डेटाइम स्पष्ट रूप से एक समयक्षेत्र के संदर्भ के बिना है - जिसे भ्रामक के रूप में देखा जा सकता है ...
assylias

1
आपके उत्तर में अनावश्यक रूप से शामिल है ZonedDateTimejava.time.Instantवर्ग के लिए एक सीधे प्रतिस्थापन है java.util.Date, दोनों हालांकि यूटीसी में एक पल का प्रतिनिधित्व करने Instantका उपयोग करता है मिलीसेकेंड के बजाय नैनोसेकंड की एक महीन संकल्प। Date.from( Instant.now() )आपका समाधान होना चाहिए था। या उस बात के लिए, बस new Date()एक ही प्रभाव, यूटीसी में वर्तमान क्षण पर कब्जा है जो।
तुलसी बॉर्क

66

tl; डॉ

java.util.Date.from(  // Transfer the moment in UTC, truncating any microseconds or nanoseconds to milliseconds.
    Instant.now() ;   // Capture current moment in UTC, with resolution as fine as nanoseconds.
)

हालांकि ऊपर उस कोड का कोई मतलब नहीं था। दोनों java.util.Dateऔर InstantUTC में एक क्षण का प्रतिनिधित्व करते हैं, हमेशा UTC में। उपरोक्त कोड का समान प्रभाव है:

new java.util.Date()  // Capture current moment in UTC.

उपयोग करने के लिए यहां कोई लाभ नहीं है ZonedDateTime। यदि आपके पास पहले से ही एक है ZonedDateTime, तो एटीसी को हटाकर यूटीसी को समायोजित करें Instant

java.util.Date.from(             // Truncates any micros/nanos.
    myZonedDateTime.toInstant()  // Adjust to UTC. Same moment, same point on the timeline, different wall-clock time.
)

अन्य उत्तर सही

उत्तर द्वारा ssoltanid सही ढंग से अपने विशिष्ट प्रश्न के पते, कैसे एक नए स्कूल java.time वस्तु (परिवर्तित करने के लिए ZonedDateTimeएक पुराने स्कूल के लिए) java.util.Dateवस्तु। InstantZonedDateTime से निकालें और पास करें java.util.Date.from()

डेटा हानि

ध्यान दें कि आप होगा डेटा नुकसान के रूप में, Instantपटरियों नैनोसेकंड के बाद से युग जबकि java.util.Dateपटरियों मिलीसेकेंड अवधि के बाद।

आरेख मिलिसेकंड, माइक्रोसेकंड और नैनोसेकंड के प्रस्तावों की तुलना करता है

आपके प्रश्न और टिप्पणियाँ अन्य मुद्दों को उठाते हैं।

सेवकों को यूटीसी में रखें

आपके सर्वर में आमतौर पर एक सर्वोत्तम अभ्यास के रूप में UTC को अपना होस्ट OS सेट होना चाहिए। जेवीएम इस जावा ओएस सेटिंग को अपने डिफ़ॉल्ट समय क्षेत्र के रूप में चुनता है, जावा कार्यान्वयन में जिसे मैं जानता हूं।

समय क्षेत्र निर्दिष्ट करें

लेकिन आपको जेवीएम के वर्तमान डिफ़ॉल्ट समय क्षेत्र पर कभी भी भरोसा नहीं करना चाहिए। होस्ट सेटिंग को चुनने के बजाय, JVM लॉन्च करते समय एक ध्वज पारित हुआ जो एक और समय क्षेत्र सेट कर सकता है। इससे भी बदतर: किसी भी समय किसी भी ऐप के किसी भी धागे में कोई भी कोड java.util.TimeZone::setDefaultरनटाइम पर उस डिफ़ॉल्ट को बदलने के लिए कॉल कर सकता है!

कैसंड्रा Timestampप्रकार

किसी भी सभ्य डेटाबेस और ड्राइवर को स्वचालित रूप से भंडारण के लिए यूटीसी को पारित तिथि को समायोजित करना चाहिए। मैं कैसंड्रा का उपयोग नहीं करता हूं, लेकिन ऐसा लगता है कि तारीख के लिए कुछ अल्पविकसित समर्थन है। प्रलेखन का कहना है कि इसका Timestampप्रकार एक ही युग से मिलीसेकंड की एक गिनती है (यूटीसी में 1970 का पहला क्षण)।

आईएसओ 8601

इसके अलावा, कैसंड्रा आईएसओ 8601 मानक प्रारूपों में स्ट्रिंग इनपुट स्वीकार करता है। सौभाग्य से, java.time आईएसओ 8601 प्रारूपों का उपयोग पार्सिंग / जनरेटिंग स्ट्रिंग्स के लिए अपनी चूक के रूप में करता है। Instantवर्ग ' toStringकार्यान्वयन अच्छी तरह से करेंगे।

परिशुद्धता: मिलेसेकंड बनाम नैनोसेकॉर्ड

लेकिन पहले हमें ZonedDateTime की नैनोसेकंड परिशुद्धता को मिलीसेकंड तक कम करने की आवश्यकता है। एक तरीका यह है कि मिलीसेकंड का उपयोग करके एक नया इंस्टेंट बनाया जाए। सौभाग्य से, java.time को मिलीसेकंड में और उससे परिवर्तित करने के लिए कुछ आसान तरीके हैं।

उदाहरण कोड

यहाँ जावा 8 अपडेट 60 में कुछ उदाहरण कोड है।

ZonedDateTime zdt = ZonedDateTime.now( ZoneId.of( "America/Montreal" ) );

Instant instant = zdt.toInstant();
Instant instantTruncatedToMilliseconds = Instant.ofEpochMilli( instant.toEpochMilli() );
String fodderForCassandra = instantTruncatedToMilliseconds.toString();  // Example: 2015-08-18T06:36:40.321Z

या इस कैसंड्रा जावा ड्राइवर डॉक के अनुसार , आप एक java.util.Dateउदाहरण पारित कर सकते हैं (भ्रमित होने की नहीं java.sqlDate)। तो आप instantTruncatedToMillisecondsऊपर के कोड में उस से एक जडेट बना सकते हैं ।

java.util.Date dateForCassandra = java.util.Date.from( instantTruncatedToMilliseconds );

यदि अक्सर ऐसा करते हैं, तो आप एक-लाइनर बना सकते हैं।

java.util.Date dateForCassandra = java.util.Date.from( zdt.toInstant() );

लेकिन यह थोड़ा उपयोगिता विधि बनाने के लिए नट होगा।

static public java.util.Date toJavaUtilDateFromZonedDateTime ( ZonedDateTime zdt ) {
    Instant instant = zdt.toInstant();
    // Data-loss, going from nanosecond resolution to milliseconds.
    java.util.Date utilDate = java.util.Date.from( instant ) ;
    return utilDate;
}

प्रश्न की तुलना में इस सभी कोड में अंतर देखें। प्रश्न का कोड ZTCedDateTime उदाहरण के समय क्षेत्र को UTC में समायोजित करने का प्रयास कर रहा था। लेकिन यह आवश्यक नहीं है। सैद्धांतिक रूप:

ZonedDateTime = झटपट + जोनआईड

हम सिर्फ इंस्टेंट भाग को निकालते हैं, जो पहले से ही यूटीसी (मूल रूप से यूटीसी में, सटीक विवरण के लिए कक्षा डॉक्टर) पढ़ें।


जावा में तिथि-समय प्रकारों की तालिका, दोनों आधुनिक और विरासत


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

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

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

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

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

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

जावा या एंड्रॉइड के किस संस्करण के साथ उपयोग करने के लिए java.time लाइब्रेरी की तालिका

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


अद्भुत विवरण, अच्छी तरह से विस्तृत। आपको बहुत - बहुत धन्यवाद!
जियानमारको एफ।

4

यहां वर्तमान प्रणाली समय को यूटीसी में परिवर्तित करने का एक उदाहरण है। इसमें ZonedDateTime को एक स्ट्रिंग के रूप में प्रारूपित करना शामिल है और फिर स्ट्रिंग ऑब्जेक्ट को java.text DateFormat का उपयोग करके किसी दिनांक ऑब्जेक्ट में पार्स किया जाएगा।

    ZonedDateTime zdt = ZonedDateTime.now(ZoneOffset.UTC);
    final DateTimeFormatter DATETIME_FORMATTER = DateTimeFormatter.ofPattern("yyyyMMdd HH:mm:ss");
    final DateFormat FORMATTER_YYYYMMDD_HH_MM_SS = new SimpleDateFormat("yyyyMMdd HH:mm:ss");
    String dateStr = zdt.format(DATETIME_FORMATTER);

    Date utcDate = null;
    try {
        utcDate = FORMATTER_YYYYMMDD_HH_MM_SS.parse(dateStr);
    }catch (ParseException ex){
        ex.printStackTrace();
    }

4

यदि आप एंड्रॉइड के लिए थ्रीटेन बैकपोर्ट का उपयोग कर रहे हैं और नए का उपयोग नहीं कर सकते हैं Date.from(Instant instant)(जिसके लिए न्यूनतम 26 एपीआई की आवश्यकता होती है)

ZonedDateTime zdt = ZonedDateTime.now();
Date date = new Date(zdt.toInstant().toEpochMilli());

या:

Date date = DateTimeUtils.toDate(zdt.toInstant());

कृपया बेसिल बॉर्क के जवाब में सलाह भी पढ़ें


1
थ्रीटेन बैकपोर्ट (और थ्रीटेनबप) में DateTimeUtilsरूपांतरण विधियों के साथ एक वर्ग शामिल है , इसलिए मैं दिनांक तिथि = DateTimeUtils.toDate (zdt.toInstant ()); यह इतना निम्न-स्तर नहीं है।
ओले वीवी

1

आप जावा 8 और बाद में निर्मित java.time कक्षाओं का उपयोग करके ऐसा कर सकते हैं ।

ZonedDateTime temporal = ...
long epochSecond = temporal.getLong(INSTANT_SECONDS);
int nanoOfSecond = temporal.get(NANO_OF_SECOND);
Date date = new Date(epochSecond * 1000 + nanoOfSecond / 1000000);

क्षमा करें, अस्थायी और ये सभी स्थिरांक कहाँ से आ रहे हैं?
मिलन कोवाचेव

@MilenKovachev एक ज़ोनडेटटाइम टेम्पोरल का एक उदाहरण है
पीटर लॉरी

धन्यवाद, लेकिन आपने उल्लेख किया होगा कि आपने अपना उत्तर संपादित कर दिया है ताकि मेरी टिप्पणी मूर्खतापूर्ण न लगे।
मिलन कोवाचेव

2
@MilenKovachev आप एक टिप्पणी हटा सकते हैं, लेकिन यह एक मूर्खतापूर्ण सवाल नहीं है।
बजे पीटर लॉरी

1
मैं यह समझने में असमर्थ हूं कि इस उत्तर को क्यों अस्वीकृत किया गया। Instantट्रैक सेकंड और नैनोसेकंड। Dateट्रैक मिलीसेकंड। एक से दूसरे में यह रूपांतरण सही है।
scottb

1

मैं इसका उपयोग करता हूं।

public class TimeTools {

    public static Date getTaipeiNowDate() {
        Instant now = Instant.now();
        ZoneId zoneId = ZoneId.of("Asia/Taipei");
        ZonedDateTime dateAndTimeInTai = ZonedDateTime.ofInstant(now, zoneId);
        try {
            return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(dateAndTimeInTai.toString().substring(0, 19).replace("T", " "));
        } catch (ParseException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        return null;
    }
}

क्योंकि Date.from(java.time.ZonedDateTime.ofInstant(now, zoneId).toInstant()); यह काम नहीं है !!! यदि आप अपने कंप्यूटर में अपना एप्लिकेशन चलाते हैं, तो यह समस्या नहीं है। लेकिन अगर आप AWS या Docker या GCP के किसी भी क्षेत्र में दौड़ते हैं, तो यह समस्या उत्पन्न करेगा। क्योंकि क्लाउड पर कंप्यूटर आपका टाइमज़ोन नहीं है। आपको अपना सही समय कोड में निर्धारित करना चाहिए। उदाहरण के लिए, एशिया / ताइपे। फिर यह AWS या Docker या GCP में सही हो जाएगा।

public class App {
    public static void main(String[] args) {
        Instant now = Instant.now();
        ZoneId zoneId = ZoneId.of("Australia/Sydney");
        ZonedDateTime dateAndTimeInLA = ZonedDateTime.ofInstant(now, zoneId);
        try {
            Date ans = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(dateAndTimeInLA.toString().substring(0, 19).replace("T", " "));
            System.out.println("ans="+ans);
        } catch (ParseException e) {
        }
        Date wrongAns = Date.from(java.time.ZonedDateTime.ofInstant(now, zoneId).toInstant());
        System.out.println("wrongAns="+wrongAns);
    }
}

1
यह 7 में से किसी भी उत्तर में सबसे जटिल तरीकों में से एक लगता है। क्या इसके कोई फायदे हैं? मुझे लगता है कि नहीं होगा। वहाँ वास्तव में स्वरूपण और पार्सिंग के माध्यम से जाने की कोई जरूरत नहीं है।
ओले वीवी

धन्यवाद आप पूछें क्योंकि दिनांक गलत है ।Ans = Date.from (java.time.ZonedDateTime.ofInstant (अब, ZoneId) .toInstant ()) ;; यह काम नहीं है!!!!!
बीहंग जंग १18 ’

मैंने अपने समय क्षेत्र में 17:08 से ठीक पहले आपको स्निपेट चलाया और मिला ans=Mon Jun 18 01:07:56 CEST 2018, जो गलत है, और फिर wrongAns=Sun Jun 17 17:07:56 CEST 2018, जो सही है।
ओले वीवी

मेरे कंप्यूटर में ऐप चलाने पर मुझे कोई समस्या नहीं है। लेकिन डॉकटर का उपयोग करते समय, यह समस्या है। क्योंकि कंप्यूटर में dozone में timezone आपका timezone नहीं है। आपको अपना सही समय कोड में निर्धारित करना चाहिए। उदाहरण के लिए, एशिया / ताइपे। फिर यह AWS, Docker, GCP या किसी भी कंप्यूटर में सही हो जाएगा।
बीहंग जंग

@ OleV.V। क्या आप समझ सकते हैं ?? या कोई प्रश्न?
beehuang

1

स्वीकृत जवाब मेरे काम नहीं आया। लौटाया गया दिनांक हमेशा स्थानीय दिनांक है न कि मूल समय क्षेत्र के लिए दिनांक। मैं UTC + 2 में रहता हूं।

//This did not work for me
Date.from(java.time.ZonedDateTime.now().toInstant()); 

मैं ZonedDateTime से सही तिथि प्राप्त करने के लिए दो वैकल्पिक तरीकों के साथ आया हूं।

आप हवाई के लिए इस ZonedDateTime कहते हैं

LocalDateTime ldt = LocalDateTime.now();
ZonedDateTime zdt = ldt.atZone(ZoneId.of("US/Hawaii"); // UTC-10

या मूल रूप से पूछे गए UTC के लिए

Instant zulu = Instant.now(); // GMT, UTC+0
ZonedDateTime zdt = zulu.atZone(ZoneId.of("UTC"));

वैकल्पिक 1

हम java.sql.Timestamp का उपयोग कर सकते हैं। यह सरल है, लेकिन यह शायद आपके प्रोग्रामिंग अखंडता में भी सेंध लगाएगा

Date date1 = Timestamp.valueOf(zdt.toLocalDateTime());

वैकल्पिक 2

हम मिल से दिनांक बनाते हैं ( पहले यहां उत्तर दिया गया है)। ध्यान दें कि स्थानीय ज़ोनऑफ़सेट एक आवश्यक है।

ZoneOffset localOffset = ZoneOffset.systemDefault().getRules().getOffset(LocalDateTime.now());
long zonedMillis = 1000L * zdt.toLocalDateTime().toEpochSecond(localOffset) + zdt.toLocalDateTime().getNano() / 1000000L;
Date date2 = new Date(zonedMillis);

0

बीहुआंग जैसे डॉकटर एप्लिकेशन के लिए टिप्पणी की गई कि आपको अपना समय क्षेत्र निर्धारित करना चाहिए।

वैकल्पिक रूप से आप withZoneSameLocal का उपयोग कर सकते हैं । उदाहरण के लिए:

2014-07-01T00: 00 + 02: 00 [GMT + 02: 00] द्वारा परिवर्तित किया गया है

Date.from(zonedDateTime.withZoneSameLocal(ZoneId.systemDefault()).toInstant())

टू जूल 01 से 00:00:00 2014 और उसके बाद

Date.from(zonedDateTime.toInstant())

से सोम जून 30 22:00:00 यूटीसी 2014


-1

यदि आप अब केवल में रुचि रखते हैं, तो बस उपयोग करें:

Date d = new Date();

मुझे अब दिलचस्पी है लेकिन UTC अब।
मिलन कोवाचेव

2
हाँ, यह अब UTC होगा, तिथि का कोई बेहतर पता नहीं है।
याकूब एकेल

3
नहीं, यह नहीं होगा। यह अब लोकल सिस्टम टाइम ज़ोन में होगा। दिनांक किसी भी टाइमज़ोन जानकारी को संग्रहीत नहीं करता है, लेकिन यह वर्तमान सिस्टम समय का उपयोग करता है और वर्तमान सिस्टम टाइमज़ोन को अनदेखा करता है, इसलिए वहाँ कभी भी इसे यूटीसी के लिए परिवर्तित नहीं करता है
डेविड

2
@ दाविद तिथि यूटीसी युग के सापेक्ष समय रखती है, इसलिए यदि आप अमेरिका में एक सिस्टम से एक नई तिथि () लेते हैं और एक अन्य वस्तु जापान में एक कंप्यूटर बनाते हैं तो वे समान होंगे (लंबे समय तक वे दोनों आंतरिक रूप से रखते हैं)।
जैकब एकेल

1
@JacobEckel - हां, लेकिन अगर आप 9am को डेट में रखते हैं जबकि आपका tz यूएस tz है और फिर JP tz में बदल कर 9am के साथ एक नई डेट बनाएं, तो डेट में इंटरनल वैल्यू अलग होगी। जैसे ही आप डीएसटी को उस मिश्रण में फेंकते हैं, आप तब तक तारीख का उपयोग नहीं कर सकते, जब तक कि आपका ऐप हमेशा यूटीसी में नहीं चलता है, जो किन्हीं भी कारणों से बदल सकता है, जिनमें से अधिकांश खराब कोड के आसपास घूमते हैं।
डेविड
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.