क्या java.sql.Timestamp timezone विशिष्ट है?


85

मुझे यूबी डेटाइम को डीबी में स्टोर करना है।
मैंने विशिष्ट टाइमज़ोन में दी गई तारीख समय को यूटीसी में बदल दिया है। उसके लिए मैंने नीचे दिए गए कोड का पालन किया।
मेरा इनपुट डेटटाइम "20121225 10:00:00 Z" टाइमज़ोन है "एशिया / कलकत्ता"
मेरा सर्वर / DB (ओरेकल) उसी टाइमज़ोन (IST) "एशिया / कलकत्ता" में चल रहा है

इस विशिष्ट समयक्षेत्र में दिनांक ऑब्जेक्ट प्राप्त करें

        String date = "20121225 10:00:00 Z";
        String timeZoneId = "Asia/Calcutta";
        TimeZone timeZone = TimeZone.getTimeZone(timeZoneId);

        DateFormat dateFormatLocal = new SimpleDateFormat("yyyyMMdd HH:mm:ss z");
                    //This date object is given time and given timezone
        java.util.Date parsedDate = dateFormatLocal.parse(date + " "  
                         + timeZone.getDisplayName(false, TimeZone.SHORT));

        if (timeZone.inDaylightTime(parsedDate)) {
            // We need to re-parse because we don't know if the date
            // is DST until it is parsed...
            parsedDate = dateFormatLocal.parse(date + " "
                    + timeZone.getDisplayName(true, TimeZone.SHORT));
        }

       //assigning to the java.sql.TimeStamp instace variable
        obj.setTsSchedStartTime(new java.sql.Timestamp(parsedDate.getTime()));

DB में स्टोर करें

        if (tsSchedStartTime != null) {
            stmt.setTimestamp(11, tsSchedStartTime);
        } else {
            stmt.setNull(11, java.sql.Types.DATE);
        }

आउटपुट

DB (oracle) ने dateTime: "20121225 10:00:00यूटीसी में दिए गए समान को संग्रहीत किया है ।

मैंने नीचे दिए गए एसक्यूएल से पुष्टि की है।

     select to_char(sched_start_time, 'yyyy/mm/dd hh24:mi:ss') from myTable

मेरा DB सर्वर भी उसी समयक्षेत्र "एशिया / कलकत्ता" पर चल रहा है

यह मुझे नीचे दिखावे देता है

  1. Date.getTime() UTC में नहीं है
  2. या टाइमस्टैम्प का डीबी में भंडारण करते समय टाइमजोन प्रभाव पड़ता है मैं यहां क्या गलत कर रहा हूं?

एक और प्रश्न:

क्या timeStamp.toString()स्थानीय टाइमज़ोन में प्रिंट होगा java.util.date? UTC नहीं?


4
आपके शीर्षक में प्रश्न का उत्तर देने के लिए, java.sql.Timestamp UTC पर आधारित है। टाइमस्टैम्प को प्रदर्शित करना समयक्षेत्र विशिष्ट है।
गिल्बर्ट ले ब्लैंक

@ गिल्बर्ट ले ब्लैंक धन्यवाद!। क्या आप मुझे जवाब दे सकते हैं "नया java.sql.Timestamp (parsedDate.getTime ())" मेरे इनपुट के लिए GMT टाइमस्टैम्प ऑब्जेक्ट लौटाएगा?
कानागावेलु सुगुमार

1
@GbertbertLeBlanc हालांकि java.sql.TimestampUTC में है, जब टाइमजोन की जानकारी के बिना किसी TIMESTAMP क्षेत्र में भंडारण किया जाता है, तो यह वर्चुअल मशीन के वर्तमान समय-क्षेत्र में समतुल्य तिथि / समय का उपयोग करता है
Mark Rotteveel

@ कनगवेलु सुगुमार: हाँ। दिनांक वर्ग की गेटटाइम विधि 1 जनवरी, 1970 से 00:00:00 GMT तक मिलीसेकंड की संख्या लौटाती है।
गिल्बर्ट ले ब्लैंक

@MarkRotteveel मार्क मुझे आपकी बात नहीं मिली "टाइमजोन की जानकारी के बिना TIMESTAMP फील्ड में स्टोर करना, यह वर्चुअल मशीन के वर्तमान टाइमज़ोन में समतुल्य तिथि / समय का उपयोग करता है"। क्या आप कृपया अपने उत्तर में विस्तार से बता सकते हैं। यह मेरे लिए अधिक उपयोगी होगा।
काणगावेलु सुगुमार

जवाबों:


105

हालांकि यह स्पष्ट रूप से निर्दिष्ट नहीं है कि setTimestamp(int parameterIndex, Timestamp x)ड्राइवरों को setTimestamp(int parameterIndex, Timestamp x, Calendar cal)javadoc द्वारा स्थापित नियमों का पालन करना है :

दिए java.sql.Timestampगए Calendarऑब्जेक्ट का उपयोग करके, दिए गए मान को निर्दिष्ट पैरामीटर सेट करता है । ड्राइवर CalendarSQL TIMESTAMPमान के निर्माण के लिए ऑब्जेक्ट का उपयोग करता है , जिसे ड्राइवर तब डेटाबेस में भेजता है। Calendarऑब्जेक्ट के साथ , ड्राइवर टाइमस्टैम्प को कस्टम टाइम ज़ोन में ध्यान में रखते हुए गणना कर सकता है। यदि कोई Calendarऑब्जेक्ट निर्दिष्ट नहीं है, तो ड्राइवर डिफ़ॉल्ट टाइम ज़ोन का उपयोग करता है, जो कि एप्लिकेशन को चलाने वाली वर्चुअल मशीन है।

जब तुम साथ बुलाते हो setTimestamp(int parameterIndex, Timestamp x) JDBC ड्राइवर के तो उस टाइम ज़ोन में टाइमस्टैम्प की तारीख और समय की गणना करने के लिए वर्चुअल मशीन के समय क्षेत्र का उपयोग करता है। यह दिनांक और समय वह है जो डेटाबेस में संग्रहीत होता है, और यदि डेटाबेस कॉलम समय क्षेत्र की जानकारी संग्रहीत नहीं करता है, तो ज़ोन के बारे में कोई भी जानकारी खो जाती है (जिसका अर्थ है कि यह डेटाबेस का उपयोग करने के लिए डेटाबेस का उपयोग करके अनुप्रयोग तक है) एक ही टाइम ज़ोन लगातार या दूसरी स्कीम के साथ आने के लिए टाइमज़ोन (यानी एक अलग कॉलम में स्टोर)।

उदाहरण के लिए: आपका स्थानीय समय क्षेत्र GMT + 2 है। आप "2012-12-25 10:00:00 UTC" स्टोर करें। डेटाबेस में संग्रहीत वास्तविक मूल्य "2012-12-25 12:00:00" है। आप इसे फिर से प्राप्त करते हैं: आप इसे फिर से "2012-12-25 10:00:00 UTC" के रूप में वापस प्राप्त करते हैं (लेकिन केवल यदि आप इसका उपयोग करके इसे पुनः प्राप्त करते हैं getTimestamp(..)), लेकिन जब कोई अन्य अनुप्रयोग समय क्षेत्र GMT + 0 में डेटाबेस तक पहुँचता है, तो यह होगा टाइमस्टैम्प को "2012-12-25 12:00:00 UTC" के रूप में पुनः प्राप्त करें।

यदि आप इसे एक अलग टाइमज़ोन में संग्रहीत करना चाहते हैं, तो आपको setTimestamp(int parameterIndex, Timestamp x, Calendar cal)आवश्यक टाइमज़ोन में कैलेंडर उदाहरण के साथ उपयोग करने की आवश्यकता है। बस यह सुनिश्चित करें कि आप मान प्राप्त करते समय एक ही टाइम ज़ोन के साथ बराबर गेट्टर का उपयोग करते हैं (यदि आप TIMESTAMPअपने डेटाबेस में बिना टाइमज़ोन जानकारी का उपयोग करते हैं)।

इसलिए, यह मानकर कि आप वास्तविक GMT टाइमज़ोन संग्रहीत करना चाहते हैं, आपको उपयोग करने की आवश्यकता है:

Calendar cal = Calendar.getInstance(TimeZone.getTimeZone("GMT"));
stmt.setTimestamp(11, tsSchedStartTime, cal);

JDBC 4.2 के साथ एक आज्ञाकारी चालक को java.time.LocalDateTime(और java.time.LocalTime) के लिए TIMESTAMP(और TIME) का समर्थन करना चाहिए get/set/updateObjectjava.time.Local*इसलिए कोई रूपांतरण (हालांकि कि समस्याओं का एक नया सेट को खोल सकता है यदि आपके कोड एक विशेष समय क्षेत्र मान था) लागू किए जाने की आवश्यकता कक्षाएं, समय क्षेत्रों के बिना कर रहे हैं।


मैं अपना समय GMT में स्टोर करना चाहता हूं। मेरा मानना ​​है कि जीएमटी में मेरा टाइमस्टैम्प है। तो मुझे क्या करना चाहिए? क्या यह सेटटैम्पैम्प (इंट पैरामीटरइंडेक्स, टाइमस्टैम्प tzGmtObj, कैलेंडर calGmtObj) है ??
कानागावेलु सुगुमर

यदि "setTimestamp (int पैरामीटरIndex, Timestamp x)" वर्चुअल मशीन के टाइमज़ोन का उपयोग करता है। कोड में x की क्या भूमिका है?
काणगावेलु सुगुमार

1
@KanagaveluSugumar सेट करने के लिए वास्तविक टाइमस्टैम्प मान है। एक चालक केवल समय-वस्तु की जानकारी के लिए कैलेंडर ऑब्जेक्ट का उपयोग करता है, न कि उसके मूल्य के लिए!
मार्क रोटेटेवेल

1
महान, यह काम कर रहा है :) मैं साबित करने के लिए बहुत समय बिताता हूं (तिथि / टाइमस्टैम्प) .getTime () मिलीसेकंड में टाइमजोन विशिष्ट समय धारण कर रहा है। अब मैं समझ गया कि यह नहीं है। यह हमेशा समय की परवाह किए बिना UTC मिलीसेकंड देता है। लेकिन (दिनांक / टाइमस्टैम्प) .toString () टाइमज़ोन विशिष्ट है। बहुत बहुत धन्यवाद।
काणगावेलु सुगुमार

4
toString()पर java.lang.Date(और java.lang.Timestamp) हमेशा आपके स्थानीय समय क्षेत्र में यह पेश करेंगे।
मार्क रोटटेवेल

35

मुझे लगता है कि सही उत्तर java.sql होना चाहिए। Timestamp समय-क्षेत्र विशिष्ट नहीं है। टाइमस्टैम्प java.util.Date का एक समग्र और एक अलग नैनोसेकंड मूल्य है। इस वर्ग में कोई समय क्षेत्र की जानकारी नहीं है। इस प्रकार दिनांक के रूप में यह वर्ग 1 जनवरी, 1970, 00:00:00 GMT + नैनो के बाद से केवल मिलीसेकंड की संख्या रखता है।

ReadyedStatement.setTimestamp (int पैरामीटरIndex, Timestamp x, Calendar cal) कैलेंडर में ड्राइवर द्वारा डिफ़ॉल्ट टाइमज़ोन को बदलने के लिए उपयोग किया जाता है। लेकिन टाइमस्टैम्प अभी भी जीएमटी में मिलीसेकंड रखता है।

एपीआई स्पष्ट नहीं है कि कैलेंडर का उपयोग करने के लिए जेडीबीसी चालक वास्तव में कैसा है। प्रदाता इसे कैसे व्याख्या करते हैं, इसके बारे में स्वतंत्र महसूस करते हैं, उदाहरण के लिए पिछली बार जब मैंने MySQL 5.5 कैलेंडर के साथ काम किया, तो ड्राइवर ने कैलेंडर की तैयारी दोनों की तैयारी में ध्यान नहीं दिया। ResestSet.getTimestamp और ResultSet.getTimestamp।


MySQL 5.5
Alex

2
मेरा मानना ​​है कि यह जावा 8+ की तरह गलत है। टाइमस्टैम्प के अंदर (क्योंकि यह java.util.Date से फैली हुई है) एक कैलेंडर विशेषता है, जिसमें एक जोनइनफ़ो विशेषता है जो वास्तव में टाइमज़ोन में शामिल है। आप अभी भी .TC (।) के साथ UTC समय प्राप्त कर सकते हैं क्योंकि टाइमस्टैम्प भी इसे संग्रहीत करता है, लेकिन यह समयबद्ध जानकारी है।
जॉर्ज

1
आपका मतलब है कि यह GMT के बजाय 1 जनवरी, 1970 से 00:00:00 UTC के बाद मिलीसेकंड की संख्या रखता है। GMT में दिन के समय की बचत होती है। 1 जनवरी, 1970 से 00:00 यूटीसी के बाद से यूनिक्स की अवधि मिलीसेकंड है।
किर्बी

6

मैसकल के लिए, हमारे पास एक सीमा है। में चालक Mysql डॉक , हमने:

MySQL कनेक्टर / J के लिए कुछ ज्ञात समस्याएँ और सीमाएँ निम्नलिखित हैं: जब कनेक्टर / J परिणाम सेट पर getTimeStamp () पद्धति का उपयोग करके दिन के समय की बचत समय (DST) स्विच दिन के लिए टाइमस्टैम्प प्राप्त करता है, तो लौटे कुछ गलत हो सकते हैं। डेटाबेस से कनेक्ट होने पर निम्नलिखित कनेक्शन विकल्पों का उपयोग करके त्रुटियों से बचा जा सकता है:

useTimezone=true
useLegacyDatetimeCode=false
serverTimezone=UTC

इसलिए, जब हम इस पैरामीटर का उपयोग नहीं करते हैं और हम setTimestamp or getTimestampकैलेंडर के साथ या बिना कैलेंडर के साथ कॉल करते हैं, तो हमारे पास jvm टाइमज़ोन में टाइमस्टैम्प है।

उदाहरण :

Jvm टाइमज़ोन GMT + 2 है। डेटाबेस में, हमारे पास एक टाइमस्टैम्प है: 1461100256 = 19/04/16 21: 10: 56,000000000 GMT

Properties props = new Properties();
props.setProperty("user", "root");
props.setProperty("password", "");
props.setProperty("useTimezone", "true");
props.setProperty("useLegacyDatetimeCode", "false");
props.setProperty("serverTimezone", "UTC");
Connection con = DriverManager.getConnection(conString, props);
......
Calendar nowGMT = Calendar.getInstance(TimeZone.getTimeZone("GMT"));
Calendar nowGMTPlus4 = Calendar.getInstance(TimeZone.getTimeZone("GMT+4"));
......
rs.getTimestamp("timestampColumn");//Oracle driver convert date to jvm timezone and Mysql convert date to GMT (specified in the parameter)
rs.getTimestamp("timestampColumn", nowGMT);//convert date to GMT 
rs.getTimestamp("timestampColumn", nowGMTPlus4);//convert date to GMT+4 timezone

पहली विधि रिटर्न: 1461100256000 = 19/04/2016 - 21:10:56 जीएमटी

दूसरी विधि रिटर्न: 1461100256000 = 19/04/2016 - 21:10:56 जीएमटी

तीसरी विधि रिटर्न: 1461085856000 = 19/04/2016 - 17:10:56 जीएमटी

ओरेकल के बजाय, जब हम समान कॉल का उपयोग करते हैं, तो हमारे पास है:

पहली विधि रिटर्न: 1461093056000 = 19/04/2016 - 19:10:56 जीएमटी

दूसरी विधि रिटर्न: 1461100256000 = 19/04/2016 - 21:10:56 जीएमटी

तीसरी विधि रिटर्न: 1461085856000 = 19/04/2016 - 17:10:56 जीएमटी

NB: Oracle के लिए मापदंडों को निर्दिष्ट करना आवश्यक नहीं है।


1
मुझे लगता है कि आप MySQL के गैर-कैलेंडर मामले के लिए उसी रूपांतरण को प्राप्त करने के लिए UTC को सत्र टाइमज़ोन सेट कर सकते हैं। " ALTER SESSION SET TIME_ZONE = 'UTC'"।
eckes

5

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

java -Duser.timezone="America/New_York" GetCurrentDateTimeZone

इसके अलावा:

to_char(new_time(sched_start_time, 'CURRENT_TIMEZONE', 'NEW_TIMEZONE'), 'MM/DD/YY HH:MI AM')

रूपांतरण को ठीक से संभालने के लिए भी मूल्य हो सकता है। यहां से ले गए


क्या मेरा मतलब है कि आप stackoverflow.com/questions/2858182/… का अनुसरण करें या आप GMT में चलने के लिए मेरा JVM एप्लिकेशन सेट करना चाहते हैं?
काणागावेलु सुगुमार

@KanagaveluSugumar अच्छी तरह से निर्भर करता है। यदि आप हर बार टाइमस्टैम्प को संशोधित करना चाहते हैं, तो इसे स्टार्टअप पर सेट करें, यदि आप केवल कुछ को संशोधित करना चाहते हैं (मतलब हर चीज से कम) तो फैशन में प्रत्येक क्वेरी को संशोधित करें जैसा कि आपके द्वारा बताई गई पोस्ट द्वारा किया गया है।
वुट 4Moo

5

जवाब है कि java.sql.Timestampगड़बड़ है और इससे बचना चाहिए। java.time.LocalDateTimeइसके बजाय उपयोग करें ।

तो यह एक गड़बड़ क्यों है? से java.sql.TimestampJavaDoc, एक java.sql.Timestampएक "पतली आवरण के आसपास है java.util.Dateकि JDBC API एक SQL TIMESTAMP मूल्य के रूप में इस पहचान करने के लिए अनुमति देता है"। से java.util.DateJavaDoc, " Dateवर्ग समन्वित यूनिवर्सल समय (UTC) को प्रतिबिंबित करने का इरादा है।" आईएसओ एसक्यूएल युक्ति से टाइमटाइम ज़ोन के बिना एक टाइमस्टैम्प "एक डेटा प्रकार है जो टाइम ज़ोन के बिना डेटाइम है"। TIMESTAMP TIMEESTAMP बिना छोटे समय के लिए एक छोटा नाम है। तो एक java.sql.Timestamp"प्रतिबिंबित" UTC जबकि एसक्यूएल टाइमस्टेप "बिना समय क्षेत्र" है।

क्योंकि java.sql.TimestampUTC दर्शाता है कि इसके तरीके रूपांतरण लागू करते हैं। यह भ्रम का कोई अंत नहीं है। SQL परिप्रेक्ष्य से यह SQL अर्थ को किसी अन्य टाइम ज़ोन में बदलने के लिए कोई मतलब नहीं है क्योंकि TIMESTAMP के पास बदलने के लिए कोई समय क्षेत्र नहीं है। 42 को फारेनहाइट में बदलने का क्या मतलब है? इसका मतलब कुछ भी नहीं है क्योंकि 42 में तापमान इकाइयां नहीं हैं। यह सिर्फ एक नंगे नंबर है। इसी तरह आप 2020-07-22T10: 38: 00 के टाइमस्टैम्प को अमेरिका / लॉस एंजिल्स में नहीं बदल सकते क्योंकि 2020-07-22T10: 30: 00 किसी भी समय क्षेत्र में नहीं है। यह यूटीसी या जीएमटी या किसी और चीज में नहीं है। यह एक नंगे तारीख का समय है।

java.time.LocalDateTimeएक नंगे तारीख का समय भी है। इसमें टाइम ज़ोन नहीं है, बिल्कुल SQL TIMESTAMP की तरह। इसका कोई भी तरीका किसी भी प्रकार के समय क्षेत्र रूपांतरण पर लागू नहीं होता है, जिससे इसके व्यवहार की भविष्यवाणी करना और समझना बहुत आसान हो जाता है। तो उपयोग न करेंjava.sql.Timestamp । का उपयोग करें java.time.LocalDateTime

LocalDateTime ldt = rs.getObject(col, LocalDateTime.class);
ps.setObject(param, ldt, JDBCType.TIMESTAMP);

तो बहुत अच्छी तरह से कहा। धन्यवाद।
ओले वीवी

2

आप अपने इच्छित क्षेत्र / क्षेत्र आईडी के लिए डेटाबेस में टाइमस्टैम्प को स्टोर करने के लिए नीचे दी गई विधि का उपयोग कर सकते हैं।

ZonedDateTime zdt = ZonedDateTime.now(ZoneId.of("Asia/Calcutta")) ;
Timestamp timestamp = Timestamp.valueOf(zdt.toLocalDateTime());

एक सामान्य गलती जो लोग करते हैं, वह LocaleDateTimeउस पल के टाइमस्टैम्प को प्राप्त करने के लिए उपयोग की जाती है जो किसी भी सूचना को आपके क्षेत्र में निर्दिष्ट करता है, भले ही आप बाद में बदलने की कोशिश करें। यह जोन को समझ नहीं आता है।

कृपया ध्यान दें Timestampकि यह वर्ग का है java.sql.Timestamp


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