PostgreSQL में दिनांक और समय डेटा संग्रहीत करने की कोई भी रणनीति, IMO, इन दो बिंदुओं पर निर्भर होनी चाहिए:
- आपका समाधान कभी नहीं होना चाहिए सर्वर या क्लाइंट टाइमज़ोन सेटिंग पर निर्भर करता है।
- वर्तमान में, PostgreSQL (अधिकांश डेटाबेस के रूप में) में पूर्ण स्टोर करने के लिए डेटाटाइप नहीं है समय क्षेत्र के साथ दिनांक और समय। इसलिए, आपको
Instant
. के बीच निर्णय लेने की आवश्यकता है या एकLocalDateTime
डेटाटाइप।
मेरी रेसिपी इस प्रकार है।
यदि आप भौतिक तत्काल . रिकॉर्ड करना चाहते हैं जब कोई विशेष घटना हुई, (एक सच्चा "टाइमस्टैम्प " , आम तौर पर कुछ निर्माण/संशोधन/हटाने की घटना), फिर उपयोग करें:
- जावा:
Instant
(जावा 8 या जोडाटाइम)। - JDBC:
java.sql.Timestamp
- पोस्टग्रेएसक्यूएल:
TIMESTAMP WITH TIMEZONE
(TIMESTAMPTZ
)
(PostgreSQL के अजीबोगरीब डेटाटाइप WITH TIMEZONE
. को अनुमति न दें /WITHOUT TIMEZONE
आपको भ्रमित करते हैं:उनमें से कोई भी वास्तव में समय क्षेत्र संग्रहीत नहीं करता है)
कुछ बॉयलरप्लेट कोड:निम्नलिखित मानते हैं कि ps
एक PreparedStatement
है , rs
एक ResultSet
और tzUTC
एक स्थिर Calendar
है UTC
. के अनुरूप वस्तु समयक्षेत्र।
public static final Calendar tzUTC = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
Instant
लिखें डेटाबेस के लिए TIMESTAMPTZ
:
Instant instant = ...;
Timestamp ts = instant != null ? Timestamp.from(instant) : null;
ps.setTimestamp(col, ts, tzUTC); // column is TIMESTAMPTZ!
पढ़ें Instant
डेटाबेस से TIMESTAMPTZ
:
Timestamp ts = rs.getTimestamp(col,tzUTC); // column is TIMESTAMPTZ
Instant inst = ts !=null ? ts.toInstant() : null;
यह सुरक्षित रूप से काम करता है यदि आपका पीजी प्रकार TIMESTAMPTZ
. है (उस स्थिति में, calendarUTC
उस कोड में कोई प्रभाव नहीं पड़ता है; लेकिन यह हमेशा सलाह दी जाती है कि डिफ़ॉल्ट टाइमज़ोन पर निर्भर न रहें)। "सुरक्षित रूप से" का अर्थ है कि परिणाम सर्वर या डेटाबेस टाइमज़ोन पर निर्भर नहीं होगा , या टाइमज़ोन जानकारी:ऑपरेशन पूरी तरह से प्रतिवर्ती है, और टाइमज़ोन सेटिंग्स के साथ जो कुछ भी होता है, आपको हमेशा वही "तत्काल समय" मिलेगा जो आपको मूल रूप से जावा की तरफ था।
यदि, टाइमस्टैम्प (भौतिक समयरेखा पर एक झटपट) के बजाय, आप एक "सिविल" स्थानीय दिनांक-समय के साथ काम कर रहे हैं (अर्थात, फ़ील्ड का सेट {year-month-day hour:min:sec(:msecs)}
), आप उपयोग करेंगे:
- जावा:
LocalDateTime
(जावा 8 या जोडाटाइम)। - JDBC:
java.sql.Timestamp
- पोस्टग्रेएसक्यूएल:
TIMESTAMP WITHOUT TIMEZONE
(TIMESTAMP
)
पढ़ें LocalDateTime
डेटाबेस से TIMESTAMP
:
Timestamp ts = rs.getTimestamp(col, tzUTC); //
LocalDateTime localDt = null;
if( ts != null )
localDt = LocalDateTime.ofInstant(Instant.ofEpochMilli(ts.getTime()), ZoneOffset.UTC);
LocalDateTime
लिखें डेटाबेस के लिए TIMESTAMP
:
Timestamp ts = null;
if( localDt != null)
ts = new Timestamp(localDt.toInstant(ZoneOffset.UTC).toEpochMilli()), tzUTC);
ps.setTimestamp(colNum,ts, tzUTC);
फिर से, यह रणनीति सुरक्षित है और आप चैन की नींद सो सकते हैं:अगर आपने 2011-10-30 23:59:30
स्टोर किया है , आप उन सटीक क्षेत्रों (घंटे =23, मिनट =59 ... आदि) को हमेशा पुनः प्राप्त करेंगे, चाहे कुछ भी हो - भले ही कल आपके पोस्टग्रेस्क्ल सर्वर (या क्लाइंट) का समय क्षेत्र बदल जाए, या आपका जेवीएम या आपका ओएस टाइमज़ोन, या यदि आपका देश अपने डीएसटी नियमों आदि को संशोधित करता है।
जोड़ा गया:यदि आप चाहते हैं (यह एक स्वाभाविक आवश्यकता है) पूर्ण डेटाटाइम विनिर्देश (एक ZonedDatetime
) को संग्रहीत करने के लिए :टाइमज़ोन के साथ टाइमस्टैम्प, जिसमें निहित रूप से पूर्ण नागरिक डेटाटाइम जानकारी - साथ ही टाइमज़ोन भी शामिल है) ... . आपको अपना खुद का भंडारण तैयार करना चाहिए, शायद खेतों की एक जोड़ी में:उपरोक्त दो प्रकार हो सकते हैं (अत्यधिक बेमानी, हालांकि पुनर्प्राप्ति और गणना के लिए कुशल), या उनमें से एक प्लस समय ऑफसेट (आप समय क्षेत्र की जानकारी खो देते हैं, कुछ गणना बन जाती है कठिन, और कुछ असंभव), या उनमें से एक प्लस टाइमज़ोन (स्ट्रिंग के रूप में; कुछ गणनाएं बेहद महंगी हो सकती हैं)।