PHP और mySQL: वर्ष 2038 बग: यह क्या है? इसे कैसे हल करें?


116

मैं दिनांक + समय को संग्रहीत करने के लिए TIMESTAMP का उपयोग करने के बारे में सोच रहा था, लेकिन मैंने पढ़ा कि इस पर वर्ष 2038 की सीमा है। बल्क में अपना प्रश्न पूछने के बजाय, मैंने इसे छोटे भागों में तोड़ना पसंद किया ताकि नौसिखिए उपयोगकर्ताओं के लिए भी इसे समझना आसान हो। इसलिए मेरा प्रश्न:

  1. वर्ष 2038 समस्या क्या है?
  2. ऐसा क्यों होता है और ऐसा होने पर क्या होता है?
  3. हम इसे कैसे हल करेंगे?
  4. क्या इसका उपयोग करने के लिए कोई संभावित विकल्प हैं, जो एक समान समस्या पैदा नहीं करते हैं?
  5. जब हम वास्तव में होते हैं, तो तथाकथित समस्या से बचने के लिए, TIMESTAMP का उपयोग करने वाले मौजूदा अनुप्रयोगों के लिए हम क्या कर सकते हैं?

अग्रिम में धन्यवाद।


1
अभी तो 28 साल होने को हैं। क्या आप अभी भी 1982 से किसी भी कंप्यूटर से संबंधित तकनीक का उपयोग कर रहे हैं? संभावना नहीं है। तो चिंता न करें, क्योंकि 2038 तक यह अब कोई मुद्दा नहीं होगा।
गॉर्डन

24
गॉर्डन, मैं एक आवेदन करता हूं जो पूर्वानुमान करता है। मेरे पास हर महीने कितना पैसा बचता है, और तब अनुमान लगा सकता हूं कि मैं कब करोड़पति बनूंगा। मेरे मामले में, 28 वर्ष इतना अधिक नहीं है, और मुझे यकीन है कि मैं एकमात्र ऐसा व्यक्ति नहीं हूं, जिसके पास अभी यह समस्या है (मैंने टाइमस्टैम्प का प्रतिनिधित्व करने के लिए 64-बिट संख्याओं का उपयोग करके इसे हल किया है)।
एमिल विक्रोस्म

2
@ ईमिल अभी 64 बिट पूर्णांक का उपयोग करके , आप अपने आप को एक ठोस समस्या का एक आसान समाधान मिल गया है। सभी के लिए लागू नहीं (या आवश्यक), लेकिन आपके usecase के लिए काम करना। बिंदु है, अगर ओपी के पास पूर्वानुमान की तरह एक ठोस समस्या नहीं है, तो यह एक दिलचस्प विषय हो सकता है, लेकिन उसे कुछ भी चिंता नहीं करनी चाहिए, क्योंकि सामान्य स्तर पर इसे हल करना एक PHP (टैग नहीं) मुद्दा है। बस मेरा 2 सी।
गॉर्डन

1
2038 तक, "YYYY-MM-DD HH: MM: SS: mmmm ..." स्ट्रिंग को पार करना सबसे सस्ता ऑपरेशन होगा जिसका आप सपना देख सकते हैं। 2038 तक, 32 बिट अप्रचलित हो जाएगा। मुझे संदेह है कि यूनिक्स टाइमस्टैम्प के रूप में हम जानते हैं कि यह तब मौजूद होगा, और अगर ऐसा होता है, तो हमारे 256 बिट सिस्टम उन तारीखों को संभाल लेंगे जो उस उम्र से बहुत आगे तक पहुंचते हैं जहां 4096 बिट सिस्टम खुश भोजन में दिए गए हैं।
सुपर कैट

8
गॉर्डन, इसके 9 साल बाद अब। TIMESTAMPS अभी भी उपयोग किया जाता है। हम अभी भी 28 साल पहले से प्रौद्योगिकी का उपयोग करते हैं। इसे वर्ल्ड वाइड वेब कहा जाता है।
sfscs

जवाबों:


149

मैंने इसे एक समुदाय विकी के रूप में चिह्नित किया है इसलिए अपने अवकाश पर संपादित करने के लिए स्वतंत्र महसूस करें।

वर्ष 2038 समस्या क्या है?

"वर्ष 2038 की समस्या (जिसे यूनिक्स मिलेनियम बग के रूप में भी जाना जाता है, Y2K समस्या के अनुरूप वाई 2 के38) कुछ कंप्यूटर सॉफ़्टवेयर को 2038 से पहले या वर्ष में विफल होने का कारण हो सकता है। समस्या सभी सॉफ़्टवेयर और सिस्टम को प्रभावित करती है जो सिस्टम को एक हस्ताक्षरित 32 के रूप में स्टोर करती है। पूर्णांक, और इस संख्या को 1 जनवरी, 1970 को 00:00:00 UTC के बाद से सेकंड की संख्या के रूप में व्याख्या करें। "


ऐसा क्यों होता है और ऐसा होने पर क्या होता है?

03:14:07 UTC से परे मंगलवार, 19 जनवरी 2038 को 'रैप अराउंड' होगा और आंतरिक रूप से एक नकारात्मक संख्या के रूप में संग्रहीत किया जाएगा, जिसे ये सिस्टम 1338, 1901 में 2038 के बजाय एक समय के रूप में व्याख्या करेंगे। यह कारण है तथ्य यह है कि UNIX युग (1 जनवरी 1970 00:00:00 GMT) के बाद से सेकंड की संख्या एक 32-बिट हस्ताक्षरित पूर्णांक के लिए कंप्यूटर के अधिकतम मूल्य को पार कर जाएगी।


हम इसे कैसे हल करेंगे?

  • लंबे डेटा प्रकारों का उपयोग करें (64 बिट्स पर्याप्त है)
  • MySQL (या MariaDB) के लिए, यदि आपको DATEकॉलम प्रकार का उपयोग करके समय की जानकारी पर विचार करने की आवश्यकता नहीं है । यदि आपको उच्च सटीकता की आवश्यकता है, तो DATETIMEइसके बजाय उपयोग करें TIMESTAMP। खबरदार कि DATETIMEकॉलम समय-सीमा के बारे में जानकारी संग्रहीत नहीं करते हैं, इसलिए आपके आवेदन को यह जानना होगा कि किस समय का उपयोग किया गया था।
  • विकिपीडिया पर वर्णित अन्य संभावित समाधान
  • एक दशक से पहले रिपोर्ट किए गए इस बग को ठीक करने के लिए MySQL देवों की प्रतीक्षा करें ।

क्या इसका उपयोग करने के लिए कोई संभावित विकल्प हैं, जो एक समान समस्या पैदा नहीं करते हैं?

डेटाबेस में स्टोर करने की तारीखों के लिए बड़े प्रकारों का उपयोग करने के लिए जहाँ भी संभव हो कोशिश करें: 64-बिट्स पर्याप्त है - जीएनयू सी और पोसिक्स / एसयूएस, या sprintf('%u'...)पीएचपी या बीसीमैथ एक्सटेंशन में एक लंबा लंबा प्रकार ।


भले ही हम 2038 में अभी तक नहीं हैं, लेकिन कुछ संभावित रूप से ब्रेकिंग केस के मामले क्या हैं?

इसलिए एक MySQL DATETIME की सीमा 1000-9999 है, लेकिन TIMESTAMP की रेंज केवल 1970-2038 है। यदि आपका सिस्टम जन्मतिथि, भविष्य की फ़ॉरवर्ड डेट्स (जैसे 30 वर्ष के बंधक), या इसी तरह के स्टोर करता है, तो आप पहले से ही इस बग में चलने वाले हैं। यदि यह समस्या होने वाली है तो फिर से TIMESTAMP का उपयोग न करें।


जब हम वास्तव में होते हैं, तो तथाकथित समस्या से बचने के लिए, TIMESTAMP का उपयोग करने वाले मौजूदा अनुप्रयोगों के लिए हम क्या कर सकते हैं?

कुछ पीएचपी अनुप्रयोग अभी भी 2038 के आसपास होंगे, हालांकि यह वेब के रूप में मुश्किल है क्योंकि अभी तक शायद ही कोई विरासत मंच है।

यहां एक डेटाबेस टेबल कॉलम को बदलने के TIMESTAMPलिए एक प्रक्रिया है DATETIME। यह एक अस्थायी कॉलम बनाने के साथ शुरू होता है:

# rename the old TIMESTAMP field
ALTER TABLE `myTable` CHANGE `myTimestamp` `temp_myTimestamp` int(11) NOT NULL;

# create a new DATETIME column of the same name as your old column
ALTER TABLE `myTable` ADD `myTimestamp` DATETIME NOT NULL;

# update all rows by populating your new DATETIME field
UPDATE `myTable` SET `myTimestamp` = FROM_UNIXTIME(temp_myTimestamp);

# remove the temporary column
ALTER TABLE `myTable` DROP `temp_myTimestamp`

साधन


2
बहुत बढ़िया। मेरे लिए, आपका जवाब सबसे पूरा है। बहुत धन्यवाद।
डेनेर

7
MySQL में, यदि भविष्य के संस्करण में अंतर्निहित स्टोरेज डाटा टाइप के TIMESTAMP को 64-बिट में बदल दिया जाए, तो आपके कोड को DATETIME में बदलने की आवश्यकता नहीं है, है ना? मुझे नहीं लगता कि किसी को भी TIMESTAMP का उपयोग करने से हतोत्साहित करना सही है क्योंकि डेटा प्रकार का इसका उद्देश्य नहीं है।
पिक्सफ्रीक

1
MySQL के हस्ताक्षरित BIGINT फ़ील्ड ऐसा लगता है कि यह टाइमस्टैम्प के भंडारण के लिए ठीक काम करेगा और मैंने MySQL 5.5 पर कुछ स्थानीय परीक्षण किए हैं जो इसकी पुष्टि करता है। स्पष्ट रूप से हस्ताक्षरित का उपयोग करना अहस्ताक्षरित से बेहतर होगा क्योंकि आप अतीत में भी तारीखों का प्रतिनिधित्व कर सकते हैं। टाइमस्टैम्प के लिए BIGINT का उपयोग नहीं करने का कोई कारण?
ज़ुलाउज़

ध्यान देने वाली एक बात, MySQL में टाइमस्टैम्प फ़ील्ड के लिए केवल वर्तमान दिनांक / समय (CURRENT_TIMESTAMP) पर ऑटो सेटिंग है। उम्मीद है, यह कार्यक्षमता अंततः सभी प्रकार की तारीखों के लिए होगी।
रे

5
यह बिल्कुल बेतुका है कि MySQL (और MariaDB) 64 बिट सिस्टम पर टाइमस्टैम्प को स्टोर करने के लिए 64 बिट पूर्णांक का उपयोग नहीं करता है। DATETIME का उपयोग करना है नहीं एक पर्याप्त समाधान है क्योंकि हम समय क्षेत्र के बारे में पता नहीं है। यह 2005 में वापस आ गया था , लेकिन फिर भी कोई फिक्स उपलब्ध नहीं है।
माइक

14

जब UNIX टाइमस्टैम्प्स का उपयोग तारीखों को संग्रहीत करने के लिए किया जाता है, तो आप वास्तव में 32 बिट्स पूर्णांक का उपयोग कर रहे हैं, जो कि 1970-01-01 के बाद से सेकंड की संख्या को ध्यान में रखता है; यूनिक्स समय देखें

वह 32 बिट्स संख्या 2038 में ओवरफ्लो होगी। यही 2038 समस्या है।


उस समस्या को हल करने के लिए, आपको अपनी तिथियों को संग्रहीत करने के लिए 32 बिट्स UNIX टाइमस्टैम्प का उपयोग नहीं करना चाहिए - जिसका अर्थ है, MySQL का उपयोग करते समय, आपको उपयोग नहीं करना चाहिए TIMESTAMP, लेकिन DATETIME( 10.3.1 देखें । DATETIME, DATE, और TIMESTAMP प्रकार :

DATETIMEप्रकार का उपयोग किया है जब आप मूल्यों है कि दोनों की तारीख और समय में जानकारी होती है की जरूरत है। समर्थित सीमा है '1000-01-01 00:00:00'करने के लिए '9999-12-31 23:59:59'

TIMESTAMPडेटा प्रकार की एक श्रृंखला है '1970-01-01 00:00:01'करने के लिए यूटीसी '2038-01-19 03:14:07'यूटीसी।


(शायद) सबसे अच्छी बात आप से बचने / ठीक करने के लिए अपने आवेदन है कि समस्या का उपयोग नहीं करने के लिए है करने के लिए क्या कर सकते हैं TIMESTAMP, लेकिनDATETIME कॉलम दिनांकों कि 1970 और 2038 के बीच नहीं हैं करने के लिए है कि के लिए।

एक छोटा सा नोट, हालांकि: बहुत उच्च शायद (सांख्यिकीय रूप से बोलना) है कि आपके आवेदन को 2038 से पहले कई बार फिर से लिखा गया होगा ^ ^ तो शायद, अगर आपको भविष्य में तारीखों का सामना नहीं करना पड़ता है , आपको अपने आवेदन के वर्तमान संस्करण के साथ उस समस्या का ध्यान नहीं रखना होगा ...


1
जानकारी के लिए +1। यहां कोशिश है कि शुरू से ही सर्वोत्तम प्रथाओं को अनुकूल बनाया जाए ताकि किसी को बाद में समस्या के बारे में चिंता न करनी पड़े। इसलिए हालाँकि अब के लिए 2038 एक मुद्दे की तरह नहीं लग सकता है, मैं सिर्फ सर्वोत्तम प्रथाओं का पालन करना चाहता हूं और प्रत्येक और प्रत्येक एप्लिकेशन के लिए इसका पालन करता हूं जो मैं बनाता हूं, शुरू से ही सही। आशा है कि समझ में आता है।
डेवनेर

हां, यह समझ में आता है, मैं आपकी बात देखता हूं। लेकिन "सबसे अच्छा अभ्यास" का अर्थ "क्या उत्तर की आवश्यकता है" भी हो सकता है - यदि आप जानते हैं कि एक टाइमस्टैम्प पर्याप्त होगा, तो एक डेटाइम का उपयोग करने की कोई आवश्यकता नहीं है (उदाहरण के लिए, संग्रहीत होने के लिए अधिक मेमोरी की आवश्यकता होती है, और अगर बात हो सकती है; आपके पास लाखों रिकॉर्ड हैं) ;; मेरे पास कुछ एप्लिकेशन हैं जिनमें मैं कुछ कॉलम (उदाहरण के लिए वर्तमान तिथि वाले कॉलम) के लिए टाइमस्टैम्प का उपयोग करता हूं, और कुछ अन्य लोगों के लिए डेटाटाइम (ऐसे कॉलम जिनमें अतीत / भविष्य की तारीखें हैं, उदाहरण के लिए)
पास्कल मार्टिन

मुझे लगता है कि आपकी प्रक्रिया भी समझ में आती है और विशेष रूप से भंडारण स्थान से संबंधित होने पर अच्छी तरह से काम करती है। यदि यह ठीक है, तो क्या मैं आपसे पूछ सकता हूं कि आपके अनुप्रयोगों में TIMESTAMP कॉलम के लिए आप किस संरचना और लंबाई का उपयोग करते हैं? धन्यवाद।
Devner

खैर, जब मैं एक TIMESTAMP का उपयोग करना चाहता हूं, तो यह 1970/2038 के बीच के मेरे "दिनांक / समय" डेटा के लिए है / और इसलिए, मैं MySQL TIMESTAMP डेटा प्रकार का उपयोग करता हूं।
पास्कल मार्टिन

जानकारी के लिए धन्यवाद। आपकी प्रतिक्रिया से, मैं समझता हूं कि यह केवल स्तंभ को TIMESTAMP घोषित करने के लिए पर्याप्त है और हमें इसके लिए कोई लंबाई प्रदान करने की आवश्यकता नहीं है (इसके विपरीत और int या var, जहाँ हम लंबाई प्रदान करते हैं)। क्या मैं सही हू?
डेवनेर

7

Google पर एक त्वरित खोज चाल करेगी: वर्ष 2038 समस्या

  1. वर्ष 2038 की समस्या (जिसे यूनिक्स मिलेनियम बग के रूप में भी जाना जाता है, Y2K38 Y2K समस्या के अनुरूप) कुछ कंप्यूटर सॉफ़्टवेयर के विफल होने से पहले या वर्ष 2038 में हो सकता है
  2. यह समस्या एक हस्ताक्षरित 32-बिट पूर्णांक के रूप में सिस्टम समय को संग्रहीत करने वाले सभी सॉफ़्टवेयर और सिस्टम को प्रभावित करती है, और 1 जनवरी, 1970 को 00:00:00 UTC के बाद से सेकंड की संख्या के रूप में इस संख्या की व्याख्या करती है। नवीनतम समय जिसे इस तरह से दर्शाया जा सकता है। 03:14:07 मंगलवार, 19 जनवरी 2038 को UTC है। इस क्षण से परे टाइम्स "चारों ओर लपेट" जाएगा और आंतरिक रूप से एक नकारात्मक संख्या के रूप में संग्रहीत किया जाएगा, जिसे ये सिस्टम 2038 के बजाय 1901 में एक तारीख के रूप में व्याख्या करेंगे।
  3. मौजूदा सीपीयू / ओएस संयोजन, मौजूदा फाइल सिस्टम, या मौजूदा बाइनरी डेटा प्रारूपों के लिए इस समस्या के लिए कोई आसान निर्धारण नहीं है

2

http://en.wikipedia.org/wiki/Year_2038_problem में अधिकांश विवरण हैं

संक्षेप में:

1) + 2) समस्या यह है कि कई सिस्टम दिनांक जानकारी को 1/1/1970 के बाद से सेकंड की संख्या के बराबर 32-बिट हस्ताक्षरित इंट के रूप में संग्रहीत करते हैं। नवीनतम तारीख जिसे इस तरह संग्रहीत किया जा सकता है मंगलवार, 19 जनवरी 2038 को 03:14:07 यूटीसी। जब ऐसा होता है, तो यह इरादा "चारों ओर लपेट" जाएगा और एक नकारात्मक संख्या के रूप में संग्रहीत किया जाएगा जिसे 1901 में एक तारीख के रूप में व्याख्या किया जाएगा। तब वास्तव में क्या होगा, सिस्टम से सिस्टम में भिन्न होता है लेकिन यह कहना पर्याप्त होता है कि यह उनमें से किसी के लिए भी अच्छा नहीं होगा!

सिस्टम के लिए जो केवल अतीत में तारीखों को संग्रहीत करता है, फिर मुझे लगता है कि आपको थोड़ी देर के लिए चिंता करने की आवश्यकता नहीं है! मुख्य समस्या उन प्रणालियों के साथ है जो भविष्य में तारीखों के साथ काम करते हैं। यदि आपके सिस्टम को भविष्य में 28 साल की तारीखों के साथ काम करने की आवश्यकता है, तो आपको अब चिंता करना शुरू कर देना चाहिए!

3) उपलब्ध वैकल्पिक तिथियों में से किसी एक का उपयोग करें या 64-बिट सिस्टम में जाएं और 64-बिट इनट्स का उपयोग करें। या डेटाबेस के लिए एक वैकल्पिक समय स्टैम्प प्रारूप का उपयोग करें (जैसे MySQL का उपयोग DATETIME के ​​लिए)

४) ३ देखें!

5) 4 देखें !!! ;)


आपके अंक ४ और ५ मुझे 'कॉल बाय संदर्भ' की याद दिलाते हैं। जिसने मेरे चेहरे पर मुस्कान ला दी। इसके लिए धन्यवाद और +1।
डेवनेर

1

Bros, यदि आपको टाइमस्टैम्प प्रदर्शित करने के लिए PHP का उपयोग करने की आवश्यकता है, तो यह UNIX_TIMESTAMP प्रारूप से बदले बिना BEST PHP समाधान है।

एक custom_date () फ़ंक्शन का उपयोग करें। इसके अंदर, DateTime का उपयोग करें। यहाँ DateTime समाधान है

जब तक आपके पास डेटाबेस में आपके टाइमस्टैम्प के रूप में UNSIGNED BIGINT (8) है। जब तक आपके पास PHP 5.2.0 ++ है


-1

जैसा कि मैंने कुछ भी अपग्रेड नहीं करना चाहा, मैंने अपने बैकएंड (MSSQL) को PHP के बजाय यह काम करने के लिए कहा!

$qry = "select DATEADD(month, 1, :date) next_date ";
$rs_tmp = $pdo->prepare($qry);
$rs_tmp->bindValue(":date", '2038/01/15');
$rs_tmp->execute();
$row_tmp = $rs_tmp->fetch(PDO::FETCH_ASSOC);

echo $row_tmp['next_date'];

एक कुशल तरीका नहीं हो सकता है, लेकिन यह काम करता है।

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