sql >> データベース >  >> RDS >> Database

2038年問題とは何ですか?

    2038年問題(Y2K38バグとも呼ばれます)は、2038-01-1903:14:07を過ぎた時間を処理するときに一部のコンピューターシステムで発生する可能性のある問題を指します。

    UnixやUnixベースのシステムなど、多くのコンピュータシステムは、グレゴリオ暦を使用して時間を計算しません。 1970年1月1日からの秒数として時間を計算します。したがって、これらのシステムでは、時間は大きな数値(つまり、1970-01-01 00:00:00から経過した秒数)として表されます。これは通常、エポック時間、Unix時間、Unixエポック時間、またはPOSIX時間と呼ばれます。これを書いているとき、Unix時間は1560913841です。そして、この次の行を書いているとき、Unix時間は1560913879に増加しています。

    2038年問題は、多くのシステムがこの数値を符号付き32ビットの2進整数として格納しているという事実が原因で発生します。符号付き32ビット整数の範囲は-2,147,483,648から2,147,483,647です。これは、表現できる最新のエポック時刻が2147483647であることを意味します。これは、2038年1月19日火曜日の03:14:07に発生します。

    その後、結果はシステムに大きく依存します。多くのシステムでは、整数のオーバーフローが発生し、それ以降は折り返され、負の数として内部に格納されます。その結果、1秒後、時刻は2038年1月19日ではなく1901年12月13日と解釈されます。

    ただし、使用しているアプリケーションによっては、結果が異なる場合もあります。オペレーティングシステムに問題がない場合でも、独自のコードに問題がある可能性があります。たとえば、Unix時間を返すカスタムコードを記述し、それを符号付き4バイト整数で格納すると、問題が発生します。このような場合、8バイト整数を使用するようにコードを書き直すだけで十分な場合があります。

    このウェブサイトはすべてデータベースに関するものなので、ここにいくつかのデータベースの例があります。

    例1-MySQL

    MySQLでは、TIMESTAMP データ型は、「1970-01-01 00:00:01.000000」UTCから「2038-01-1903:14:07.999999」までの日付/時刻をサポートします。したがって、このデータ型を使用するデータベースにはY2K38バグがあると言えます。

    MySQLには、UNIX_TIMESTAMP()と呼ばれる組み込み関数もあります。 ご想像のとおり、これはUnixタイムスタンプを返します。

    UNIX_TIMESTAMP() 関数は、Unix時間に使用する日付(つまり、「1970-01-01 00:00:00」UTCから指定した時間までの秒数)を指定できるオプションの引数を受け入れます。引数値の有効な範囲は、TIMESTAMPの場合と同じです。 データ型は、「1970-01-01 00:00:01.000000」UTCから「2038-01-1903:14:07.999999」UTCです。この関数に範囲外の日付を渡すと、0が返されます。 。

    この関数を使用して、「2038-01-19 03:14:07.999999」を過ぎた日付からUnix時間を返そうとすると、次のようになります。

    SELECT UNIX_TIMESTAMP('2038-01-20') Result;
    

    結果:

    +--------+
    | Result |
    +--------+
    |      0 |
    +--------+
    

    0を取得します 日付引数がサポートされている範囲外であるためです。

    関連するバグレポートが2005年にMySQLチームに対して提起されましたが(詳細の一部は異なっているように見えますが)、この記事の執筆時点ではまだ対処されていません。

    TIMESTAMPの制限に対処するために、同様の問題も発生しました。 データ型。これもまだ対処されていません。

    例2– SQL Server

    SQL Serverには現在、MySQLのUNIX_TIMESTAMPに相当するものはありません。 働き。したがって、エポック時間を返す必要がある場合は、次のようにする必要があります。

    SELECT DATEDIFF(SECOND,'1970-01-01', GETUTCDATE());
    

    これは、2038年問題より前の日付には問題ありません。その日付以降は、DATEDIFF()が原因で、問題が発生します。 関数は結果をintとして返します データ・タイプ。 int データ型の範囲は-2^31(-2,147,483,648)から2 ^ 31-1(2,147,483,647)です。

    「2038-01-1903:14:07」より後のエポック時間を戻そうとすると、次のようになります。

    SELECT DATEDIFF(SECOND,'1970-01-01', '2038-01-19 03:14:08') AS 'Result';
    

    結果:

    The datediff function resulted in an overflow. The number of dateparts separating two date/time instances is too large. Try to use datediff with a less precise datepart.
    

    幸い、DATEDIFF_BIG()もあります 関数。これは、結果を bigint として返すことを除いて、まったく同じことを行います。 データ型。

    したがって、この問題を解決するために、前の例を次のように書き直すことができます。

    SELECT DATEDIFF_BIG(SECOND,'1970-01-01 00:00:00', '2038-01-19 03:14:08') AS 'Result';
    

    結果:

    +------------+
    | Result     |
    |------------|
    | 2147483648 |
    +------------+
    

    bigint データ型は8バイトを使用します( int の4バイトとは対照的) )、したがって、DATEDIFF_BIG()に切り替えるかどうかを決定する必要があります 今または後で。アプリケーションが将来の日付を処理する場合は、後で実行するのが賢明かもしれません。


    1. MySQLに値を挿入するためのBashスクリプト

    2. Postgresクエリウィンドウのパラメータを使用してアドホックSQLをテストする方法

    3. MySQL Errno 150

    4. AzurePortalとWorkbenchを使用してMySQLServer用のAzureデータベースを作成およびデプロイする方法