ruby on rails - रेल और PostgreSQL में समय क्षेत्र पूरी तरह से अनदेखा




ruby-on-rails ruby-on-rails-3 (2)

मैं रेल और पोस्टग्रेस में तिथियों और समय से निपट रहा हूं और इस मुद्दे पर चल रहा हूं:

डेटाबेस यूटीसी में है।

उपयोगकर्ता रेल ऐप में पसंद का समय-क्षेत्र सेट करता है, लेकिन इसका उपयोग केवल समय की तुलना करने के लिए स्थानीय समय प्राप्त करने के दौरान किया जाता है।

उपयोगकर्ता 17 मार्च, 2012, 7 बजे एक समय स्टोर करता है। मैं टाइमज़ोन रूपांतरण या टाइमज़ोन को संग्रहीत नहीं करना चाहता हूं। मैं सिर्फ उस तारीख और समय को सहेजना चाहता हूं। इस तरह यदि उपयोगकर्ता ने अपना समय क्षेत्र बदल दिया, तो यह अभी भी 17 मार्च, 2012, 7 बजे दिखाएगा।

मैं उपयोगकर्ताओं को स्थानीय समय क्षेत्र में वर्तमान समय 'पहले' या 'बाद' रिकॉर्ड प्राप्त करने के लिए केवल निर्दिष्ट समय क्षेत्र का उपयोग करता हूं।

मैं वर्तमान में समय क्षेत्र के बिना 'टाइमस्टैम्प' का उपयोग कर रहा हूं, लेकिन जब मैं रिकॉर्ड्स पुनर्प्राप्त करता हूं, रेल (?) उन्हें ऐप में समय क्षेत्र में परिवर्तित कर देता है, जो मैं नहीं चाहता हूं।

Appointment.first.time
 => Fri, 02 Mar 2012 19:00:00 UTC +00:00 

चूंकि डेटाबेस में रिकॉर्ड्स यूटीसी के रूप में सामने आते हैं, मेरा हैक वर्तमान समय लेना है, समय क्षेत्र को 'date.strptime (str, "% m /% d /% y")' के साथ हटाएं और फिर मेरा इसके साथ पूछताछ करें:

.where("time >= ?", date_start)

ऐसा लगता है कि आसपास के समय क्षेत्र को अनदेखा करने का एक आसान तरीका होना चाहिए। कोई विचार?


यदि आप डिफ़ॉल्ट रूप से यूटीसी में सौदा करना चाहते हैं:

config/application.rb , जोड़ें:

config.time_zone = 'UTC'

फिर, यदि आप वर्तमान उपयोगकर्ता टाइमज़ोन नाम को स्टोर करते हैं तो current_user.timezone आप कह सकते हैं।

post.created_at.in_time_zone(current_user.timezone)

current_user.timezone एक वैध टाइमज़ोन नाम होना चाहिए, अन्यथा आपको ArgumentError: Invalid Timezone मिलेगा ArgumentError: Invalid Timezone , पूर्ण सूची देखें।


timestamp without time zone लिए डेटा प्रकार timestamp संक्षिप्त नाम timestamp without time zone
अन्य विकल्प timestamp timestamp with time zone लिए छोटा timestamp with time zone

timestamptz शब्द / समय परिवार में शाब्दिक रूप से पसंदीदा प्रकार है। यह typispreferred सेट typispreferred सेट है, जो प्रासंगिक हो सकता है:

युग

आंतरिक रूप से , टाइमस्टैम्प को एक epoch से गिनती के रूप में संग्रहीत किया जाता है। पोस्टग्रेस यूटीसी में वर्ष 2000 के पहले दिन के पहले पल के युग का उपयोग करता है, यानी, 2000-01-01T00: 00: 00Z। गिनती संख्या को स्टोर करने के लिए आठ octets का उपयोग किया जाता है। संकलन समय विकल्प के आधार पर, वह संख्या या तो है:

  • एक 8-बाइट पूर्णांक (डिफ़ॉल्ट), एक आंशिक दूसरे के 0 से 6 अंक के साथ
  • एक फ्लोटिंग पॉइंट नंबर (बहिष्कृत), एक आंशिक दूसरे के 0 से 10 अंकों के साथ, जहां परिशुद्धता तेजी से युग से दूर मूल्यों के लिए घट जाती है।
    आधुनिक पोस्टग्रेस इंस्टॉलेशन 8-बाइट पूर्णांक का उपयोग करते हैं।

ध्यान दें कि पोस्टग्रेस यूनिक्स समय का उपयोग नहीं करता है। पोस्टग्रेस 'युग यूनिक्स' 1 9-01-01-01 के बजाय 2000-01-01 का पहला पल है। जबकि यूनिक्स समय में पूरे सेकंड का संकल्प होता है, पोस्टग्रेस सेकेंड के अंश रखता है।

timestamp

यदि आप डेटा प्रकार timestamp को परिभाषित करते हैं [without time zone] आप पोस्टग्रेज़ को बता रहे हैं: "मैं समय क्षेत्र को स्पष्ट रूप से प्रदान नहीं कर रहा हूं, इसके बजाय वर्तमान समय क्षेत्र मानता हूं। पोस्टग्रेर्स टाइमस्टैम्प को सहेजता है - एक समय क्षेत्र संशोधक को अनदेखा करते हुए यदि आपको जोड़ना चाहिए एक!

जब आप बाद में उस timestamp प्रदर्शित करते हैं, तो आप जो भी सचमुच दर्ज करते हैं उसे वापस ले जाते हैं। उसी समय क्षेत्र सेटिंग सभी ठीक है। यदि सत्र के लिए समय क्षेत्र सेटिंग बदलती है, तो timestamp का अर्थ भी है - मान वही रहता है।

timestamptz

timestamp with time zone संचालन काफी अलग है। मैं यहां मैनुअल उद्धृत करता हूं :

timestamp with time zone लिए, आंतरिक रूप से संग्रहीत मूल्य हमेशा यूटीसी (सार्वभौमिक समन्वयित समय ...) में होता है

बोल्ड जोर मेरा है। समय क्षेत्र स्वयं कभी संग्रहित नहीं होता है । यह एक इनपुट संशोधक है जो यूटीसी टाइमस्टैम्प के अनुसार गणना करता है, जिसे संग्रहीत किया जाता है - या आउटपुट संशोधक को प्रदर्शित करने के लिए स्थानीय समय की गणना करने के लिए प्रयुक्त होता है - संलग्न समय क्षेत्र ऑफ़सेट के साथ। यदि आप इनपुट पर timestamptz लिए ऑफसेट नहीं जोड़ते हैं, तो सत्र की वर्तमान समय क्षेत्र सेटिंग माना जाता है। सभी कंप्यूटेशंस यूटीसी टाइमस्टैम्प मानों के साथ किए जाते हैं। यदि आपको एक से अधिक समय क्षेत्र से निपटना है (या हो सकता है), timestamptz उपयोग करें।

libpq या libpq या libpq (जैसे पीजी मणि के साथ रूबी) के माध्यम से संचार करने वाले किसी भी एप्लिकेशन को वर्तमान समय क्षेत्र के लिए टाइमस्टैम्प प्लस ऑफसेट के साथ या अनुरोधित समय क्षेत्र (नीचे देखें) के अनुसार प्रस्तुत किया जाता है। यह समय में हमेशा एक ही बिंदु है , केवल प्रदर्शन प्रारूप भिन्न होता है। या, जैसा मैनुअल इसे रखता है :

सभी टाइमज़ोन-जागरूक तिथियां और समय यूटीसी में आंतरिक रूप से संग्रहीत होते हैं। वे क्लाइंट को प्रदर्शित होने से पहले TimeZone कॉन्फ़िगरेशन पैरामीटर द्वारा निर्दिष्ट जोन में स्थानीय समय में परिवर्तित हो जाते हैं।

इस सरल उदाहरण पर विचार करें (psql में):

db=# SELECT timestamptz '2012-03-05 20:00+03';
      timestamptz
------------------------
 2012-03-05 18:00:00+01

बोल्ड जोर मेरा है। यहाँ क्या हुआ?
मैंने इनपुट शाब्दिक के लिए एक मनमाना समय क्षेत्र ऑफसेट +3 चुना है। पोस्टग्रेज़ के लिए, यह यूटीसी टाइमस्टैम्प 2012-03-05 17:00:00 इनपुट करने के कई तरीकों में से एक है। क्वेरी का नतीजा मेरे परीक्षण में वियना / ऑस्ट्रिया की वर्तमान समय क्षेत्र सेटिंग के लिए प्रदर्शित होता है , जिसमें सर्दी के दौरान ऑफसेट +1 और ग्रीष्मकालीन समय के दौरान +2 : 2012-03-05 18:00:00+01 , क्योंकि यह सर्दियों के समय में गिरता है।

पोस्टग्रेस पहले ही भूल चुका है कि यह मान कैसे दर्ज किया गया है। यह सब याद है मूल्य और डेटा प्रकार है। एक दशमलव संख्या की तरह। numeric '003.4' , numeric '3.40' या numeric '+3.4' - सभी परिणाम सटीक समान आंतरिक मान में होते हैं।

AT TIME ZONE

जैसे ही आप इस तर्क पर समझ पाते हैं, आप जो कुछ भी चाहते हैं वह कर सकते हैं। अब जो कुछ याद आ रहा है, वह एक विशिष्ट समय क्षेत्र के अनुसार टाइमस्टैम्प अक्षरों की व्याख्या या प्रतिनिधित्व करने का एक साधन है। यही वह जगह है जहां AT TIME ZONE निर्माण आता है। दो अलग-अलग उपयोग के मामले हैं। timestamptz को timestamptz में परिवर्तित किया जाता है और इसके विपरीत।

यूटीसी timestamptz दर्ज करने के लिए 2012-03-05 17:00:00+0 :

SELECT timestamp '2012-03-05 17:00:00' AT TIME ZONE 'UTC'

... जो बराबर है:

SELECT timestamptz '2012-03-05 17:00:00 UTC'

ईएसटी timestamp (पूर्वी मानक समय) के रूप में समय पर एक ही बिंदु प्रदर्शित करने के लिए:

SELECT timestamp '2012-03-05 17:00:00' AT TIME ZONE 'UTC' AT TIME ZONE 'EST'

यह सही है, AT TIME ZONE 'UTC' दो बार । पहला timestamp वैल्यू को (दिए गए) यूटीसी टाइमस्टैम्प टाइप timestamptz वापस करने के रूप में व्याख्या करता है। दूसरा timestamptz को दिए गए समय क्षेत्र 'ईएसटी' में timestamp में परिवर्तित करता है - समय क्षेत्र में ईएसटी समय-समय पर इस अद्वितीय बिंदु पर प्रदर्शित करता है।

उदाहरण

SELECT ts AT TIME ZONE 'UTC'
FROM  (
   VALUES
      (1, timestamptz '2012-03-05 17:00:00+0')
    , (2, timestamptz '2012-03-05 18:00:00+1')
    , (3, timestamptz '2012-03-05 17:00:00 UTC')
    , (4, timestamp   '2012-03-05 11:00:00'  AT TIME ZONE '+6') 
    , (5, timestamp   '2012-03-05 17:00:00'  AT TIME ZONE 'UTC') 
    , (6, timestamp   '2012-03-05 07:00:00'  AT TIME ZONE 'US/Hawaii')  -- ①
    , (7, timestamptz '2012-03-05 07:00:00 US/Hawaii')                  -- ①
    , (8, timestamp   '2012-03-05 07:00:00'  AT TIME ZONE 'HST')        -- ①
    , (9, timestamp   '2012-03-05 18:00:00+1')  -- ② loaded footgun!
      ) t(id, ts);

उसी यूटीसी टाइमस्टैम्प 2012-03-05 17:00:00 एक टाइमस्टैम्प्ट्ज कॉलम के साथ 8 (या 9) समान पंक्तियां 2012-03-05 17:00:00 । 9वीं पंक्ति प्रकार मेरे समय क्षेत्र में काम करने के लिए होता है, लेकिन एक बुरा जाल है। निचे देखो।

Zone पंक्तियों के समय के साथ समय क्षेत्र नाम और समय क्षेत्र संक्षेप के साथ पंक्तियां 6 - 8 डीएसटी (डेलाइट सेविंग टाइम) के अधीन हैं और वर्तमान में नहीं हो सकती हैं। 'US/Hawaii' जैसे समय क्षेत्र का नाम डीएसटी नियमों और सभी ऐतिहासिक बदलावों से अवगत है, जबकि HST जैसे संक्षेप में एक निश्चित ऑफसेट के लिए सिर्फ एक गूंगा कोड है। आपको गर्मी / मानक समय के लिए एक अलग संक्षेप में जोड़ना पड़ सकता है। नाम दिए गए समय क्षेत्र में किसी भी टाइमस्टैम्प को सही तरीके से व्याख्या करता है। संक्षेप में सस्ता है, लेकिन दिए गए टाइमस्टैम्प के लिए सही होना चाहिए:

डेलाइट सेविंग टाइम अब तक के सबसे चमकीले विचारों में से एक नहीं है।

② पंक्ति 9, भारित फुटगुन के रूप में चिह्नित मेरे लिए काम करता है , लेकिन केवल संयोग से। यदि आप स्पष्ट रूप से timestamp [without time zone] लिए शाब्दिक रूप से डाले जाते हैं, तो किसी भी समय क्षेत्र ऑफसेट को अनदेखा कर दिया जाता है ! केवल नंगे टाइमस्टैम्प का उपयोग किया जाता है। कॉलम प्रकार से मेल खाने के लिए मान को स्वचालित रूप से timestamptz जाया जाता है। इस चरण के लिए, वर्तमान सत्र की timezone सेटिंग माना जाता है, जो मेरे मामले (यूरोप / वियना) में एक ही समय क्षेत्र +1 होता है। लेकिन शायद आपके मामले में नहीं - जिसके परिणामस्वरूप एक अलग मूल्य होगा। संक्षेप में: timestamptz अक्षर को timestamp डालें या आप समय क्षेत्र ऑफसेट खो देते हैं।

आपके सवाल

उपयोगकर्ता 17 मार्च, 2012, 7 बजे एक समय स्टोर करता है। मैं टाइमज़ोन रूपांतरण या टाइमज़ोन को संग्रहीत नहीं करना चाहता हूं।

समय क्षेत्र स्वयं कभी संग्रहित नहीं होता है। यूटीसी टाइमस्टैम्प दर्ज करने के लिए ऊपर दिए गए तरीकों में से एक का उपयोग करें।

मैं उपयोगकर्ताओं को स्थानीय समय क्षेत्र में वर्तमान समय 'पहले' या 'बाद' रिकॉर्ड प्राप्त करने के लिए केवल निर्दिष्ट समय क्षेत्र का उपयोग करता हूं।

आप अलग-अलग समय क्षेत्रों में सभी ग्राहकों के लिए एक क्वेरी का उपयोग कर सकते हैं।
पूर्ण वैश्विक समय के लिए:

SELECT * FROM tbl WHERE time_col > (now() AT TIME ZONE 'UTC')::time

स्थानीय घड़ी के अनुसार समय के लिए:

SELECT * FROM tbl WHERE time_col > now()::time

पृष्ठभूमि की जानकारी से थक नहीं, अभी तक? timestamp





timezone