सबसे पहले, PostgreSQL का समय संभालना और अंकगणित शानदार है और विकल्प 3 सामान्य मामले में ठीक है। हालांकि, यह समय और टाइमज़ोन का एक अधूरा दृश्य है और इसे पूरक किया जा सकता है:
- उपयोगकर्ता वरीयता के रूप में उपयोगकर्ता के समय क्षेत्र का नाम संग्रहीत करें (उदाहरण के लिए
America/Los_Angeles
, नहीं -0700
)।
- उपयोगकर्ता घटनाओं / समय डेटा को उनके संदर्भ के फ्रेम में स्थानीय प्रस्तुत किया है (सबसे अधिक संभावना यूटीसी से एक ऑफसेट, जैसे
-0700
)।
- आवेदन में,
UTC
एक TIMESTAMP WITH TIME ZONE
कॉलम का उपयोग करके समय को संग्रहीत और संग्रहीत करें।
- वापसी समय एक उपयोगकर्ता के समय क्षेत्र (से यानी परिवर्तित करने के लिए स्थानीय अनुरोध करता है
UTC
करने के लिए America/Los_Angeles
)।
- अपने डेटाबेस है सेट
timezone
करने के लिए UTC
।
यह विकल्प हमेशा काम नहीं करता है क्योंकि उपयोगकर्ता के समय क्षेत्र को प्राप्त करना कठिन हो सकता है और इसलिए TIMESTAMP WITH TIME ZONE
हल्के अनुप्रयोगों के लिए उपयोग करने की हेज सलाह । उस ने कहा, मुझे इस विकल्प 4 के कुछ पृष्ठभूमि पहलुओं के बारे में अधिक विस्तार से बताएं।
विकल्प 3 की तरह, इसका कारण यह WITH TIME ZONE
है कि जिस समय कुछ हुआ है वह समय में एक निरपेक्ष क्षण है। WITHOUT TIME ZONE
एक सापेक्ष समय क्षेत्र देता है। कभी भी, कभी भी, कभी भी पूर्ण और सापेक्ष टाइमस्टैम्प्स का मिश्रण न करें।
एक प्रोग्रामेटिक और स्थिरता के दृष्टिकोण से, सुनिश्चित करें कि सभी गणना यूटीसी को समय क्षेत्र के रूप में उपयोग कर रहे हैं। यह एक PostgreSQL आवश्यकता नहीं है, लेकिन यह अन्य प्रोग्रामिंग भाषाओं या वातावरण के साथ एकीकरण करते समय मदद करता है। एक की स्थापना CHECK
सुनिश्चित करें कि समय स्टाम्प स्तंभ के लिए लिखने बनाने के लिए स्तंभ पर एक समय क्षेत्र ऑफसेट है 0
एक रक्षात्मक स्थिति है कि रोकता है कीड़े के कुछ वर्गों (जैसे एक स्क्रिप्ट एक फाइल करने के लिए डेटा उदासीनता और कुछ और एक का उपयोग कर समय डेटा सॉर्ट करता शाब्दिक प्रकार)। फिर से, PostgreSQL को तिथि गणना सही ढंग से करने या समय क्षेत्र के बीच परिवर्तित करने की आवश्यकता नहीं है (अर्थात PostgreSQL किसी भी दो मनमाने समय क्षेत्रों के बीच समय बदलने में बहुत माहिर है)। यह सुनिश्चित करने के लिए कि डेटाबेस में डेटा शून्य से भरा गया है:
CREATE TABLE my_tbl (
my_timestamp TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW(),
CHECK(EXTRACT(TIMEZONE FROM my_timestamp) = '0')
);
test=> SET timezone = 'America/Los_Angeles';
SET
test=> INSERT INTO my_tbl (my_timestamp) VALUES (NOW());
ERROR: new row for relation "my_tbl" violates check constraint "my_tbl_my_timestamp_check"
test=> SET timezone = 'UTC';
SET
test=> INSERT INTO my_tbl (my_timestamp) VALUES (NOW());
INSERT 0 1
यह 100% सही नहीं है, लेकिन यह एक मजबूत पर्याप्त एंटी-फ़ुटशूटिंग उपाय प्रदान करता है जो सुनिश्चित करता है कि डेटा पहले से ही यूटीसी में परिवर्तित हो गया है। यह कैसे करना है, इस पर बहुत सारी राय है, लेकिन यह मेरे अनुभव से व्यवहार में सबसे अच्छा लगता है।
डेटाबेस टाइम ज़ोन हैंडलिंग की आलोचनाएँ काफी हद तक सही हैं (बहुत सी डेटाबेस हैं जो इसे बड़ी अक्षमता से संभालते हैं), हालांकि टाइमस्टैम्प और टाइमज़ोन की पोस्टग्रेज़क्यूएल की हैंडलिंग बहुत बढ़िया (कुछ "सुविधाओं" के बावजूद यहाँ और वहाँ है)। उदाहरण के लिए, ऐसी एक विशेषता:
-- Make sure we're all working off of the same local time zone
test=> SET timezone = 'America/Los_Angeles';
SET
test=> SELECT NOW();
now
-------------------------------
2011-05-27 15:47:58.138995-07
(1 row)
test=> SELECT NOW() AT TIME ZONE 'UTC';
timezone
----------------------------
2011-05-27 22:48:02.235541
(1 row)
ध्यान दें कि AT TIME ZONE 'UTC'
समय क्षेत्र की जानकारी स्ट्रिप्स और TIMESTAMP WITHOUT TIME ZONE
आपके लक्ष्य के संदर्भ के फ्रेम ( UTC
) का उपयोग करके एक रिश्तेदार बनाती है ।
जब एक अधूरी से परिवर्तित TIMESTAMP WITHOUT TIME ZONE
एक करने के लिए TIMESTAMP WITH TIME ZONE
, लापता समय क्षेत्र अपने कनेक्शन से विरासत में मिली है:
test=> SET timezone = 'America/Los_Angeles';
SET
test=> SELECT EXTRACT(TIMEZONE_HOUR FROM NOW());
date_part
-----------
-7
(1 row)
test=> SELECT EXTRACT(TIMEZONE_HOUR FROM TIMESTAMP WITH TIME ZONE '2011-05-27 22:48:02.235541');
date_part
-----------
-7
(1 row)
-- Now change to UTC
test=> SET timezone = 'UTC';
SET
-- Create an absolute time with timezone offset:
test=> SELECT NOW();
now
-------------------------------
2011-05-27 22:48:40.540119+00
(1 row)
-- Creates a relative time in a given frame of reference (i.e. no offset)
test=> SELECT NOW() AT TIME ZONE 'UTC';
timezone
----------------------------
2011-05-27 22:48:49.444446
(1 row)
test=> SELECT EXTRACT(TIMEZONE_HOUR FROM NOW());
date_part
-----------
0
(1 row)
test=> SELECT EXTRACT(TIMEZONE_HOUR FROM TIMESTAMP WITH TIME ZONE '2011-05-27 22:48:02.235541');
date_part
-----------
0
(1 row)
तल - रेखा:
- उपयोगकर्ता के टाइम ज़ोन को नामित लेबल (उदा
America/Los_Angeles
) के रूप में संग्रहीत करें और UTC (जैसे -0700
) से ऑफसेट न करें
- जब तक एक गैर-शून्य ऑफसेट को संग्रहीत करने के लिए एक सम्मोहक कारण नहीं है, तब तक सब कुछ के लिए यूटीसी का उपयोग करें
- इनपुट त्रुटि के रूप में सभी गैर-शून्य यूटीसी समय का इलाज करें
- कभी भी सापेक्ष और पूर्ण टाइमस्टैम्प का मिश्रण और मिलान न करें
- भी उपयोग
UTC
के रूप में timezone
डेटाबेस यदि संभव हो तो में
रैंडम प्रोग्रामिंग लैंग्वेज नोट: पाइथन का datetime
डेटा प्रकार निरपेक्ष बनाम सापेक्ष समय के बीच अंतर को बनाए रखने में बहुत अच्छा है (यद्यपि आप जब तक आप इसे PyTZ जैसी लाइब्रेरी के साथ पूरक नहीं करते हैं, तब तक निराशा होती है )।
संपादित करें
मुझे सापेक्ष बनाम पूर्ण के बीच के अंतर को थोड़ा और अधिक स्पष्ट करने दें।
किसी घटना को रिकॉर्ड करने के लिए निरपेक्ष समय का उपयोग किया जाता है। उदाहरण: "उपयोगकर्ता 123 लॉग इन" या "एक स्नातक समारोह 2011-05-28 2:00 पीएसटी पर शुरू होता है।" अपने स्थानीय समय क्षेत्र के बावजूद, यदि आप उस स्थान पर टेलीपोर्ट कर सकते हैं जहां घटना हुई है, तो आप हो रही घटना को देख सकते हैं। किसी डेटाबेस में अधिकांश समय डेटा निरपेक्ष है (और इसलिए TIMESTAMP WITH TIME ZONE
आदर्श रूप से +0 ऑफसेट के साथ होना चाहिए और एक पाठ लेबल विशेष टाइमज़ोन को नियंत्रित करने वाले नियमों का प्रतिनिधित्व करता है - ऑफ़सेट नहीं)।
एक रिश्तेदार घटना एक निश्चित-समय-निर्धारित समय क्षेत्र के दृष्टिकोण से किसी चीज़ के समय को रिकॉर्ड या शेड्यूल करना होगा। उदाहरण: "हमारे व्यवसाय के दरवाजे सुबह 8 बजे खुलते हैं और रात 9 बजे बंद होते हैं", चलो हर सोमवार को सुबह 7 बजे साप्ताहिक नाश्ते की बैठक के लिए मिलते हैं, "या" हर शाम 8 बजे हैलोवीन। " सामान्य तौर पर, घटनाओं के लिए टेम्प्लेट या कारखाने में सापेक्ष समय का उपयोग किया जाता है, और निरपेक्ष समय का उपयोग लगभग सभी चीजों के लिए किया जाता है। एक दुर्लभ अपवाद है जो इंगित करने के लायक है जो सापेक्ष समय के मूल्य को चित्रित करना चाहिए। भविष्य की घटनाओं के लिए जो भविष्य में काफी दूर हैं जहां उस समय के बारे में अनिश्चितता हो सकती है जिस समय कुछ हो सकता है, एक रिश्तेदार टाइमस्टैम्प का उपयोग करें। यहाँ एक वास्तविक दुनिया उदाहरण है:
यह वर्ष 2004 है मान लीजिए और आप अमेरिका के पश्चिमी तट (यानी को दोपहर 1 बजे से 2008 में 31 अक्टूबर एक प्रसव का समय निर्धारित करने की जरूरत है America/Los_Angeles
/ PST8PDT
)। यदि आप उस समय का उपयोग करते हुए संग्रहीत करते हैं ’2008-10-31 21:00:00.000000+00’::TIMESTAMP WITH TIME ZONE
, तो वितरण को दोपहर 2 बजे दिखाया जाता है क्योंकि अमेरिकी सरकार ने 2005 के ऊर्जा नीति अधिनियम को पारित किया था जिसने दिन के समय की बचत के समय को नियंत्रित करने वाले नियमों को बदल दिया था। 2004 में जब डिलीवरी का समय निर्धारित किया गया था, तो यह तारीख 10-31-2008
पैसिफिक स्टैंडर्ड टाइम ( +8000
) थी, लेकिन वर्ष 2005 में शुरू होने वाले + टाइमज़ोन डेटाबेस ने माना कि 10-31-2008
पैसिफिक डेलाइट सेविंग टाइम (होगा)+0700
)। समय क्षेत्र के साथ एक रिश्तेदार टाइमस्टैम्प स्टोर करने से एक सही डिलीवरी शेड्यूल हो जाता है क्योंकि एक रिश्तेदार टाइमस्टैम्प कांग्रेस की बीमार-सूचना छेड़छाड़ के लिए प्रतिरक्षा है। जहाँ शेड्यूलिंग चीज़ों के लिए सापेक्ष बनाम निरपेक्ष समय का उपयोग करने के बीच की कटऑफ एक अस्पष्ट रेखा है, लेकिन मेरे अंगूठे का नियम यह है कि भविष्य में किसी भी चीज़ के लिए 3-6mo से अधिक समय के लिए शेड्यूलिंग करना रिश्तेदार टाइमस्टैम्प का उपयोग करना चाहिए (अनुसूचित = निरपेक्ष बनाम नियोजित =) रिश्तेदार ???)।
अन्य / रिश्तेदार समय के अंतिम प्रकार है INTERVAL
। उदाहरण: "उपयोगकर्ता लॉग करने के 20 मिनट बाद सत्र समाप्त हो जाएगा"। एक INTERVAL
सही ढंग से या तो पूर्ण timestamps (साथ इस्तेमाल किया जा सकता TIMESTAMP WITH TIME ZONE
) या रिश्तेदार timestamps ( TIMESTAMP WITHOUT TIME ZONE
)। यह कहना भी उतना ही सही है, "एक सफल सत्र (login_utc + session_duration) के बाद एक उपयोगकर्ता सत्र 20 मिनट की अवधि समाप्त हो जाता है" या "हमारी सुबह की नाश्ते की बैठक केवल 60 मिनट (आवर्ती_स्टार्ट_टाइम + मीटिंग_ लंबित)" हो सकती है।
भ्रम की अंतिम बिट्स: DATE
, TIME
, TIME WITHOUT TIME ZONE
और TIME WITH TIME ZONE
सभी रिश्तेदार डेटा प्रकार हैं। उदाहरण के लिए: '2011-05-28'::DATE
आपके पास कोई समय क्षेत्र की जानकारी नहीं होने के कारण एक रिश्तेदार तिथि का प्रतिनिधित्व करता है जिसका उपयोग मध्यरात्रि को पहचानने के लिए किया जा सकता है। इसी तरह, '23:23:59'::TIME
सापेक्ष है क्योंकि आप या तो समय क्षेत्र या DATE
समय द्वारा प्रतिनिधित्व नहीं जानते हैं । यहां तक कि '23:59:59-07'::TIME WITH TIME ZONE
, आप नहीं जानते कि क्या DATE
होगा। और अंत में, DATE
समय क्षेत्र वास्तव में नहीं है DATE
, यह एक है TIMESTAMP WITH TIME ZONE
:
test=> SET timezone = 'America/Los_Angeles';
SET
test=> SELECT '2011-05-11'::DATE AT TIME ZONE 'UTC';
timezone
---------------------
2011-05-11 07:00:00
(1 row)
test=> SET timezone = 'UTC';
SET
test=> SELECT '2011-05-11'::DATE AT TIME ZONE 'UTC';
timezone
---------------------
2011-05-11 00:00:00
(1 row)
डेटाबेस में दिनांक और समय क्षेत्र डालना अच्छी बात है, लेकिन आसानी से गलत परिणाम प्राप्त करना आसान है। समय की जानकारी को सही और पूरी तरह से संग्रहीत करने के लिए न्यूनतम अतिरिक्त प्रयास की आवश्यकता होती है, हालांकि इसका मतलब यह नहीं है कि अतिरिक्त प्रयास की हमेशा आवश्यकता होती है।