PHPとmySQL:2038年のバグ:それは何ですか?それを解決するには?


116

TIMESTAMPを使用して日付と時刻を格納することを考えていましたが、2038年の制限があることを読みました。質問をまとめて尋ねるのではなく、小さな部分に分割して、初心者でも簡単に理解できるようにしました。だから私の質問:

  1. 2038年問題とは正確には何ですか?
  2. なぜそれが発生し、それが発生するとどうなりますか?
  3. どうすれば解決できますか?
  4. 同様の問題を引き起こさない、可能な代替手段はありますか?
  5. いわゆる問題が実際に発生したときに、それを回避するために、TIMESTAMPを使用する既存のアプリケーションに対して何ができるでしょうか。

前もって感謝します。


1
それはまだ28年です。1982年からまだコンピュータ関連のテクノロジーを使用していますか?ありそうもない。したがって、心配しないでください。2038年までに問題がなくなる可能性があるためです。
Gordon

24
ゴードン、私は予測を行うアプリケーションを作成します。私は毎月持っているお金を節約し、私が億万長者になる時期を見積もることができます。私の場合、28年はそれほど長くはなく、私がこの問題を抱えているのは私だけではないと確信しています(タイムスタンプを表すために64ビットの数値を使用して解決しました)。
EmilVikström、2010年

2
@Emil 今すぐ 64ビット整数を使用することで、具体的な問題の簡単な解決策を見つけました。誰にも適用できない(または必要とされる)が、ユースケースに応じて機能する。ポイントは、OPに予測のような具体的な問題がない場合、これは興味深いトピックかもしれませんが、一般的なレベルでこれを解決することはPHP(タグに注意)の問題ではないため、心配する必要はありません。ちょうど私の2c。
Gordon

1
2038年までに、文字列 "YYYY-MM-DD HH:MM:SS:mmmm ..."の解析は、夢のような最も安価な操作になります。2038年までに、32ビットは廃止されます。私が知っているUnixタイムスタンプは当時存在するのではないかと思います。存在する場合、256ビットシステムは、4096ビットシステムが幸せな食事で提供される年齢をはるかに超える日付を処理します。
スーパーキャット

8
ゴードン、その9年後の現在。TIMESTAMPSは引き続き使用されます。28年前の技術を今も使用しています。それはワールドワイドウェブと呼ばれています。
sfscs

回答:


149

これをコミュニティウィキとしてマークしましたので、ご自由に編集してください。

2038年問題とは正確には何ですか?

「2038年の問題(Unix Millennium Bug、Y2K38はY2K問題の類義語として知られています)により、一部のコンピュータソフトウェアが2038年以前または2038年に失敗する可能性があります。この問題は、システム時刻を署名付きで保存するすべてのソフトウェアとシステムに影響します32ビット整数。この数値は、1970年1月1日のUTC 00:00:00からの秒数として解釈されます。」


なぜそれが発生し、それが発生するとどうなりますか?

2038年1月19日火曜日の03:14:07 UTCを超える時間は「折り返し」、負の数として内部に格納されます。これらのシステムは、2038年ではなく1901年12月13日の時間として解釈します。これは、 UNIXエポック(1970年1月1日00:00:00 GMT)からの秒数が、コンピューターの32ビット符号付き整数の最大値を超えたという事実。


どうすれば解決できますか?

  • 長いデータ型を使用する(64ビットで十分)
  • MySQL(またはMariaDB)では、時間情報が必要ない場合は、DATE列タイプの使用を検討してください。より高い精度が必要な場合は、ではDATETIMEなくを使用してくださいTIMESTAMPDATETIME列にはタイムゾーンに関する情報が格納されないことに注意してください。そのため、アプリケーションはどのタイムゾーンが使用されたかを知る必要があります。
  • ウィキペディアに記載されている他の可能な解決策
  • MySQL開発者が10年以上前に報告されたこのバグを修正するのを待ちます。

同様の問題を引き起こさない、可能な代替手段はありますか?

データベースに日付を格納するために可能な限り大きな型を使用してみてください。64ビットで十分sprintf('%u'...)です。GNUC とPOSIX / SuS、またはPHPまたはBCmath拡張ではlong long型です。


まだ2038年になっていないのに、壊れる可能性のあるユースケースは何ですか?

したがって、MySQL DATETIMEの範囲は1000〜9999ですが、TIMESTAMPの範囲は1970〜2038のみです。システムに生年月日、将来のフォワード日(たとえば、30年の住宅ローン)などが保存されている場合、すでにこのバグに遭遇しています。繰り返しになりますが、これが問題になる場合は、TIMESTAMPを使用しないでください。


いわゆる問題が実際に発生したときに、それを回避するために、TIMESTAMPを使用する既存のアプリケーションに対して何ができるでしょうか。

2038年にはまだPHPアプリケーションはほとんどありませんが、Webがレガシープラットフォームであることはほとんどないため、予測することは困難です。

ここで変換するデータベーステーブルのカラム変更するためのプロセスである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
驚くばかり。私にとって、あなたの答えは最も完全です。どうもありがとう。
Devner、2010年

7
MySQLでは、将来のバージョンでTIMESTAMPの基礎となるストレージデータタイプを64ビットに変更する場合、コードをDATETIMEに変更する必要はありませんよね。そのデータ型には目的があるので、誰かがTIMESTAMPを使用しないようにするのが正しいことだとは思いません。
pixelfreak 2013年

1
MySQLの署名されたBIGINTフィールドは、タイムスタンプの格納にうまく機能するようです。MySQL5.5でローカルテストを行って、動作することを確認しました。もちろん、過去の日付も表すことができるので、signedを使用する方がunsignedよりも優れています。タイムスタンプにBIGINTを使用しない理由はありますか?
zuallauz 2013年

MySQLには、タイムスタンプフィールドの現在の日付/時刻(CURRENT_TIMESTAMP)のみの自動設定があります。うまくいけば、この機能は最終的にすべての日付タイプに移植されます。
レイ

5
MySQL(およびMariaDB)が64ビット整数を使用して64ビットシステムにタイムスタンプを格納しないのは、まったくばかげています。タイムゾーンがわからないため、DATETIMEの使用は適切なソリューションではありません。これは2005年報告されましたが、まだ修正はありません。
マイク

14

UNIXタイムスタンプを使用して日付を格納する場合、実際には1970-01-01からの秒数をカウントする32ビット整数を使用しています。Unix Timeを参照

その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'とUTC '2038-01-19 03:14:07'UTCを。


(おそらく)あなたは問題が使用しないことであることを回避/修正へのアプリケーションにできる最善のことTIMESTAMPが、DATETIME1970年から2038年の間ではありません日付が含まれている必要はあり列について。

ただし、1つの小さな注意:おそらく(統計的に言えば)アプリケーションが2038年までに何度か書き直されている可能性が非常に高い^^したがって、将来の日付を処理する必要がない場合は、 、アプリケーションの現在のバージョンでその問題に対処する必要はありません...


1
+1情報。ここでの試みは、最初からベストプラクティスを適用して、後で問題を心配する必要がないようにすることです。したがって、今のところ2038年は問題のように聞こえないかもしれませんが、私はベストプラクティスに従って、最初から作成するすべてのアプリケーションについて、それに従ってください。それが理にかなっていると思います。
Devner、2010年

はい、それは理にかなっています、私はあなたの主張を理解しています。しかし、「ベストプラクティス」は「ニーズに答えるもの」を意味することもあります。タイムスタンプで十分であることがわかっている場合は、日時を使用する必要はありません(たとえば、格納するためにより多くのメモリを必要とする場合など)。あなたは何百万ものレコードを持っています);; 一部の列(たとえば、現在の日付を含む列)にタイムスタンプを使用し、他のいくつかの列(たとえば、過去/未来の日付を含む列)にタイムスタンプを使用するアプリケーションがあります
Pascal MARTIN

あなたの手順も理にかなっていて、特に収納スペースに関してはうまくいくと思います。それが問題なければ、アプリケーションのTIMESTAMP列に一般的にどのような構造と長さを使用するかを尋ねてもよいですか?ありがとう。
Devner、2010年

まあ、私がTIMESTAMPを使用したい場合、それは私の「日付/時刻」データが1970から2038の間に収まるためです–したがって、MySQL TIMESTAMPデータ型を使用します。
Pascal MARTIN

情報をありがとう。あなたの応答から、列をTIMESTAMPとして宣言するだけで十分であり、長さを提供する必要がないことを理解しています(長さを提供するintまたはvarとは異なります)。私は正しいですか?
Devner、2010年

7

Googleで簡単に検索するとうまくいきます:2038年問題

  1. 2038年の問題(Unix Millennium Bug、Y2K38はY2K問題の類推として知られています)により、一部のコンピューターソフトウェアが2038年以前または2038年に失敗する可能性があります。
  2. この問題は、システム時刻を符号付き32ビット整数として保存するすべてのソフトウェアとシステムに影響し、この数値を1970年1月1日の00:00:00 UTCからの秒数として解釈します。この方法で表すことができる最新の時刻2038年1月19日火曜日の03:14:07 UTCです。この時点を超える時間は「折り返し」、負の数値として内部に保存されます。これらのシステムは、2038ではなく1901の日付として解釈します。
  3. 既存のCPU / OSの組み合わせ、既存のファイルシステム、または既存のバイナリデータ形式については、この問題の簡単な修正はありません

2

http://en.wikipedia.org/wiki/Year_2038_problemにほとんどの詳細があります

要約すれば:

1)+ 2)問題は、多くのシステムが1970年1月1日からの秒数に等しい32ビットの符号付き整数として日付情報を格納することです。このように保存できる最新の日付は、2038年1月19日火曜日の03:14:07 UTCです。これが発生すると、intは「折り返し」、負の数値として保存され、1901年の日付として解釈されます。そのとき正確に何が起こるかは、システムによって異なりますが、おそらくそれらのいずれにも適していないと言えば十分です!

過去の日付のみを保存するシステムの場合、しばらく心配する必要はないと思います!主な問題は、将来の日付を処理するシステムにあります。システムが28年後の日付で動作する必要がある場合は、今すぐ心配する必要があります。

3)使用可能な代替日付形式の1つを使用するか、64ビットシステムに移動して64ビット整数を使用します。または、データベースの場合は別のタイムスタンプ形式を使用します(たとえば、MySQLの場合はDATETIMEを使用します)

4)3を参照してください!

5)4を参照してください!!! ;)


ポイント4と5は、「参照による呼び出し」を思い出させます。それは私の顔に笑顔をもたらしました。同じことをありがとう&+1。
Devner

1

Bros、タイムスタンプを表示するためにPHPを使用する必要がある場合、これはUNIX_TIMESTAMPフォーマットから変更しない最高の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'];

効率的な方法ではないかもしれませんが、機能します。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.