php - MySQL डेटाटाइम फ़ील्ड और डेलाइट बचत समय-मैं "अतिरिक्त" घंटे का संदर्भ कैसे दूं?




datetime timestamp dst (6)

मैं अमेरिका / न्यूयॉर्क टाइमज़ोन का उपयोग कर रहा हूं। पतन में हम एक घंटे वापस "वापस आते हैं" प्रभावी रूप से 2 घंटे पर एक घंटे प्रभावी ढंग से "प्राप्त" करते हैं। संक्रमण बिंदु पर निम्नलिखित होता है:

यह 01:59:00 -04: 00 है
फिर 1 मिनट बाद यह बन जाता है:
01:00:00 -05: 00

तो यदि आप बस "1:30 बजे" कहते हैं तो यह संदिग्ध है कि आप पहली बार 1:30 रोल या दूसरे के बारे में बता रहे हैं या नहीं। मैं शेड्यूलिंग डेटा को एक MySQL डेटाबेस में सहेजने की कोशिश कर रहा हूं और यह निर्धारित नहीं कर सकता कि समय को सही तरीके से कैसे बचाया जाए।

यहां समस्या है:
"2009-11-01 00:30:00" 200 9-11-01 00:30:00 -04: 00 के रूप में आंतरिक रूप से संग्रहीत किया जाता है
"2009-11-01 01:30:00" 200 9-11-01 01:30:00 -05: 00 के रूप में आंतरिक रूप से संग्रहीत किया जाता है

यह ठीक है और काफी उम्मीद है। लेकिन मैं 01:30:00 -04: 00 को कुछ भी कैसे बचा सकता हूं? documentation ऑफ़सेट निर्दिष्ट करने के लिए कोई समर्थन नहीं दिखाता है और तदनुसार, जब मैंने ऑफ़सेट निर्दिष्ट करने का प्रयास किया है तो इसे विधिवत अनदेखा कर दिया गया है।

एकमात्र समाधान मैंने सोचा है कि सर्वर को एक टाइमज़ोन में सेट करना शामिल है जो डेलाइट बचत समय का उपयोग नहीं करता है और मेरी स्क्रिप्ट में आवश्यक परिवर्तन करता है (मैं इसके लिए PHP का उपयोग कर रहा हूं)। लेकिन ऐसा प्रतीत नहीं होता है कि यह आवश्यक होना चाहिए।

किसी भी सुझाव के लिए बहुत धन्यवाद।


Answers

मैं पृष्ठों की यात्राओं की लॉगिंग गिनती और ग्राफ में गिनती प्रदर्शित करने पर काम कर रहा था (फ्लोट jQuery प्लगइन का उपयोग करके)। मैंने टेस्ट डेटा के साथ टेबल भर दिया और सब कुछ ठीक लग रहा था, लेकिन मैंने देखा कि ग्राफ के अंत में एक्स-अक्ष पर लेबल के अनुसार अंक एक दिन बंद थे। परीक्षा के बाद मैंने देखा कि दिन 2015-10-25 के लिए दृश्य गणना डेटाबेस से दो बार पुनर्प्राप्त की गई थी और फ्लोट को पास कर दिया गया था, इसलिए इस दिन के एक दिन बाद दाएं स्थानांतरित हो गए थे।
थोड़ी देर के लिए मेरे कोड में एक बग की तलाश करने के बाद मुझे एहसास हुआ कि यह तारीख तब होती है जब डीएसटी होता है। तब मैं इस SO पृष्ठ पर आया ...
... लेकिन सुझाए गए समाधानों की आवश्यकता के लिए एक ओवरकिल था या उनके पास अन्य नुकसान थे। मैं संदिग्ध टाइमस्टैम्प के बीच अंतर करने में सक्षम नहीं होने के बारे में बहुत चिंतित नहीं हूं। मुझे सिर्फ प्रति दिन रिकॉर्ड गिनने और प्रदर्शित करने की आवश्यकता है।

सबसे पहले, मैं दिनांक सीमा पुनर्प्राप्त करता हूं:

SELECT 
    DATE(MIN(created_timestamp)) AS min_date, 
    DATE(MAX(created_timestamp)) AS max_date 
FROM page_display_log
WHERE item_id = :item_id

फिर, एक लूप में, min_date शुरू होता है, max_date दिन के साथ समाप्त होता है, एक दिन के चरण ( 60*60*24 ), मैं गणना प्राप्त कर रहा हूं:

for( $day = $min_date_timestamp; $day <= $max_date_timestamp; $day += 60 * 60 * 24 ) {
    $query = "
        SELECT COUNT(*) AS count_per_day
        FROM page_display_log
        WHERE 
            item_id = :item_id AND
            ( 
                created_timestamp BETWEEN 
                '" . date( "Y-m-d 00:00:00", $day ) . "' AND
                '" . date( "Y-m-d 23:59:59", $day ) . "'
            )
    ";
    //execute query and do stuff with the result
}

मेरी समस्या का मेरा अंतिम और त्वरित समाधान यह था:

$min_date_timestamp += 60 * 60 * 2; // To avoid DST problems
for( $day = $min_date_timestamp; $day <= $max_da.....

इसलिए मैं दिन की शुरुआत में लूप को नहीं देख रहा हूं , लेकिन दो घंटे बाद । दिन अभी भी वही है, और मैं अभी भी सही मायने रखता हूं, क्योंकि मैं टाइमस्टैम्प के वास्तविक समय के बावजूद दिन के 00:00:00 और 23:59:59 के बीच रिकॉर्ड के लिए डेटाबेस से स्पष्ट रूप से पूछता हूं। और जब समय एक घंटे तक कूदता है, तो मैं अभी भी सही दिन में हूं।

नोट: मुझे पता है कि यह 5 साल पुराना धागा है, और मुझे पता है कि यह ओपीएस प्रश्न का उत्तर नहीं है, लेकिन यह मेरे जैसे लोगों की मदद कर सकता है जिन्होंने इस पृष्ठ का सामना किया है जो मैंने वर्णित समस्या का समाधान ढूंढ रहे हैं।


मुझे यह मेरे उद्देश्यों के लिए पता चला है। मैं जो कुछ सीखा वह सारांशित करूंगा (क्षमा करें, ये नोट वर्बोज़ हैं; वे मेरे भविष्य के रेफ़रल के लिए जितना अधिक हैं)।

मेरी पिछली टिप्पणियों में से एक में मैंने जो कहा, उसके विपरीत, DATETIME और TIMESTAMP फ़ील्ड अलग-अलग व्यवहार करते हैं। TIMESTAMP फ़ील्ड्स (जैसे दस्तावेज़ इंगित करते हैं) जो भी आप उन्हें "YYYY-MM-DD hh: mm: ss" प्रारूप में भेजते हैं और इसे अपने वर्तमान टाइमज़ोन से यूटीसी समय में परिवर्तित करते हैं। जब भी आप डेटा पुनर्प्राप्त करते हैं तो विपरीत पारदर्शी होता है। DATETIME फ़ील्ड इस रूपांतरण को नहीं बनाते हैं। वे जो भी आप उन्हें भेजते हैं उन्हें लेते हैं और इसे सीधे स्टोर करते हैं।

न तो DATETIME और न ही TIMESTAMP फ़ील्ड प्रकार डीएसटी को देखते हुए एक टाइमज़ोन में डेटा को सटीक रूप से संग्रहीत कर सकते हैं । यदि आप "200 9-11-01 01:30:00" स्टोर करते हैं तो फ़ील्ड में 1:30 बजे के संस्करण को अलग करने का कोई तरीका नहीं है - -04: 00 या -05: 00 संस्करण।

ठीक है, इसलिए हमें अपने डेटा को एक गैर डीएसटी टाइमज़ोन (जैसे यूटीसी) में स्टोर करना होगा। TIMESTAMP फ़ील्ड इस डेटा को सटीक रूप से संभालने में असमर्थ हैं क्योंकि मैं समझाऊंगा: यदि आपका सिस्टम किसी डीएसटी टाइमज़ोन पर सेट है तो आप TIMESTAMP में जो भी डालते हैं वह हो सकता है कि आप वापस न आएं। भले ही आप इसे पहले से ही यूटीसी में परिवर्तित कर चुके डेटा को भेज दें, फिर भी यह डेटा आपके स्थानीय टाइमज़ोन में मान लेगा और यूटीसी में एक और रूपांतरण करेगा। यह टाइमस्टैम्प-लागू स्थानीय-टू-यूटीसी-बैक-टू-लोकल राउंडट्रिप हानिकारक है जब आपका स्थानीय टाइमज़ोन डीएसटी ("200-11-11-01 01:30:00" मानचित्रों को 2 अलग-अलग संभावित समयों से देखता है)।

DATETIME के ​​साथ आप अपने डेटा को किसी भी समय क्षेत्र में संग्रहीत कर सकते हैं और आश्वस्त रहें कि आप जो कुछ भी भेजते हैं उसे वापस ले लेंगे (आपको हानिकारक राउंडट्रिप रूपांतरणों में मजबूर नहीं किया जाता है जो TIMESTAMP फ़ील्ड आपके ऊपर फॉइस्ट करते हैं)। तो समाधान एक DATETIME फ़ील्ड का उपयोग करना है और आपके सिस्टम समय क्षेत्र से जो भी गैर-डीएसटी जोन आप इसे सहेजना चाहते हैं, उस क्षेत्र में सहेजने से पहले (मुझे लगता है कि यूटीसी शायद सबसे अच्छा विकल्प है)। यह आपको अपनी स्क्रिप्टिंग भाषा में रूपांतरण तर्क बनाने की अनुमति देता है ताकि आप "200 9-11-01 01:30:00 -04: 00" या "2009-11-01 01:30" के यूटीसी समकक्ष को स्पष्ट रूप से सहेज सकें: 00 -05: 00 "।

ध्यान देने योग्य एक और महत्वपूर्ण बात यह है कि यदि आप अपनी तिथियों को डीएसटी टीजेड में संग्रहीत करते हैं तो MySQL की दिनांक / समय गणित कार्य डीएसटी सीमाओं के आसपास ठीक से काम नहीं करते हैं। तो यूटीसी में सहेजने के लिए और भी अधिक कारण।

संक्षेप में अब मैं यह करता हूं:

डेटाबेस से डेटा पुनर्प्राप्त करते समय:

एक सटीक यूनिक्स टाइमस्टैम्प प्राप्त करने के लिए MySQL के बाहर यूटीसी के रूप में डेटाबेस से डेटा की स्पष्ट रूप से व्याख्या करें। मैं PHP के स्ट्रेटोटाइम () फ़ंक्शन या इसके डेटटाइम क्लास का उपयोग करता हूं। इसे MySQL के CONVERT_TZ () या UNIX_TIMESTAMP () फ़ंक्शंस का उपयोग करके MySQL के अंदर विश्वसनीय रूप से नहीं किया जा सकता है क्योंकि CONVERT_TZ केवल 'YYYY-MM-DD hh: mm: ss' मान आउटपुट करेगा जो अस्पष्टता समस्याओं से पीड़ित है, और UNIX_TIMESTAMP () इसे मानता है इनपुट सिस्टम टाइमज़ोन में है, समय-समय पर डेटा को वास्तव में संग्रहीत नहीं किया गया था (यूटीसी)।

डेटा को डेटाबेस में संग्रहीत करते समय:

अपनी तिथि को सटीक यूटीसी समय में बदलें जिसे आप MySQL के बाहर चाहते हैं। उदाहरण के लिए: PHP की डेटटाइम कक्षा के साथ आप "200 9-11-01 1:30:00 ईएसटी" से "200 9-11-01 1:30:00 ईएसटी" निर्दिष्ट कर सकते हैं, फिर इसे यूटीसी में परिवर्तित करें और सही यूटीसी समय को सहेजें अपने डेटाटाइम फ़ील्ड में।

ओह। हर किसी के इनपुट और मदद के लिए बहुत बहुत धन्यवाद। उम्मीद है कि यह किसी और को सड़क के नीचे कुछ सिरदर्द बचाता है।

बीटीडब्ल्यू, मैं इसे MySQL 5.0.22 और 5.0.27 पर देख रहा हूं


लेकिन मैं 01:30:00 -04: 00 को कुछ भी कैसे बचा सकता हूं?

आप यूटीसी में कनवर्ट कर सकते हैं जैसे:

SELECT CONVERT_TZ('2009-11-29 01:30:00','-04:00','+00:00');

इससे भी बेहतर, तिथियों को documentation फ़ील्ड के रूप में सहेजें। यह हमेशा यूटीसी में संग्रहीत होता है, और यूटीसी गर्मी / सर्दियों के समय के बारे में नहीं जानता है।

आप CONVERT_TZ का उपयोग कर यूटीसी से लोकटाइम में कनवर्ट कर सकते हैं:

SELECT CONVERT_TZ(UTC_TIMESTAMP(),'+00:00','SYSTEM');

जहां '00: 00 'यूटीसी है, टाइमज़ोन से, और' सिस्टम 'ओएस का स्थानीय टाइमज़ोन है जहां MySQL चलाता है।


मुझे लगता है कि माइकहविटमैन के web.ivy.net/~carton/rant/MySQL-timezones.txt में इन MySQL सीमाओं का सबसे अच्छा व्यावहारिक समाधान है: जब आप कनेक्ट करते हैं तो सत्र टाइमज़ोन को यूटीसी पर सेट करें:

SET SESSION time_zone = '+0:00'

फिर आप इसे यूनिक्स टाइमस्टैम्प भेजें और सब कुछ ठीक होना चाहिए।


MySQL की दिनांक प्रकार, स्पष्ट रूप से, टूटी हुई हैं और जब तक आपका सिस्टम निरंतर ऑफ़सेट टाइमज़ोन पर सेट नहीं होता है, जैसे यूटीसी या जीएमटी -5। (मैं MySQL 5.0.45 का उपयोग कर रहा हूँ)

ऐसा इसलिए है क्योंकि आप डेलाइट सेविंग टाइम समाप्त होने से पहले घंटे के दौरान किसी भी समय स्टोर नहीं कर सकते हैं । इससे कोई फर्क नहीं पड़ता कि आप इनपुट तिथियां कैसे करते हैं, प्रत्येक डेट फ़ंक्शन इन समयों का इलाज करेगा जैसे कि वे स्विच के बाद के घंटे के दौरान होते हैं।

मेरा सिस्टम का टाइमज़ोन America/New_York । आइए 1257051600 (सूर्य, 01 नवंबर 200 9 06:00:00 +0100) संग्रहित करने का प्रयास करें।

यहां मालिकाना अंतराल वाक्यविन्यास का उपयोग कर रहा है:

SELECT UNIX_TIMESTAMP('2009-11-01 00:00:00' + INTERVAL 3599 SECOND); # 1257051599
SELECT UNIX_TIMESTAMP('2009-11-01 00:00:00' + INTERVAL 3600 SECOND); # 1257055200

SELECT UNIX_TIMESTAMP('2009-11-01 01:00:00' - INTERVAL 1 SECOND); # 1257051599
SELECT UNIX_TIMESTAMP('2009-11-01 01:00:00' - INTERVAL 0 SECOND); # 1257055200

यहां तक ​​कि FROM_UNIXTIME() भी सटीक समय नहीं लौटाएगा।

SELECT UNIX_TIMESTAMP(FROM_UNIXTIME(1257051599)); # 1257051599
SELECT UNIX_TIMESTAMP(FROM_UNIXTIME(1257051600)); # 1257055200

विचित्र रूप से पर्याप्त, DATETIME अभी भी "खोए गए" घंटे के भीतर स्टोर और लौटाएगा (केवल स्ट्रिंग फॉर्म में!) जब डीएसटी शुरू होता है (उदाहरण के लिए 2009-03-08 02:59:59 )। लेकिन किसी भी MySQL फ़ंक्शन में इन तिथियों का उपयोग जोखिम भरा है:

SELECT UNIX_TIMESTAMP('2009-03-08 01:59:59'); # 1236495599
SELECT UNIX_TIMESTAMP('2009-03-08 02:00:00'); # 1236495600
# ...
SELECT UNIX_TIMESTAMP('2009-03-08 02:59:59'); # 1236495600
SELECT UNIX_TIMESTAMP('2009-03-08 03:00:00'); # 1236495600

टेकवे: यदि आपको साल में हर बार स्टोर और पुनर्प्राप्त करने की आवश्यकता है, तो आपके पास कुछ अवांछनीय विकल्प हैं:

  1. सिस्टम टाइमज़ोन जीएमटी + कुछ निरंतर ऑफसेट पर सेट करें। जैसे यूटीसी
  2. आईएनटी के रूप में स्टोर तिथियां (जैसे हारून की खोज की गई, TIMESTAMP भी विश्वसनीय नहीं है)

  3. DATETIME प्रकार का बहाना कुछ स्थिर ऑफ़सेट टाइमज़ोन है। उदाहरण के लिए यदि आप America/New_York , तो अपनी तिथि जीएमटी -5 में MySQL के बाहर कनवर्ट करें, फिर डेटाटाइम के रूप में स्टोर करें (यह आवश्यक हो जाता है: हारून का जवाब देखें)। फिर आपको MySQL की दिनांक / समय फ़ंक्शंस का उपयोग करके बहुत सावधानी बरतनी चाहिए, क्योंकि कुछ मानते हैं कि आपके मान सिस्टम टाइमज़ोन के हैं, अन्य (एएसपी समय अंकगणितीय कार्य) "टाइमज़ोन अज्ञेयवादी" हैं (वे व्यवहार कर सकते हैं जैसे कि समय यूटीसी है)।

हारून और मुझे संदेह है कि ऑटो-जनरेटिंग टाइमस्टैम्प कॉलम भी टूटा हुआ है। 2009-11-01 01:30 -0400 और 2009-11-01 01:30 -0500 2009-11-01 01:30 -0400 दोनों अस्पष्ट 2009-11-01 01:30 रूप में संग्रहीत किए जाएंगे।


मैं आमतौर पर विकास कोड में सरल डीबगिंग के लिए पहला तरीका उपयोग करता हूं। उत्पादन के लिए इसकी अनुशंसा नहीं की जाती है। सबसे अच्छा तरीका अपवाद फेंकना है, जिसे आप प्रोग्राम के अन्य हिस्सों में पकड़ सकते हैं और कुछ त्रुटि को संभालने में कामयाब रहे हैं।

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





php mysql datetime timestamp dst