MySQLのUNIX_TIMESTAMPにある程度未来の日付を渡すと0になる

databasemysql

以下、MySQL5.6で遭遇した。

MySQLのUNIX_TIMESTAMPは DATETIME文字列などを引数にとり、UNIXタイムスタンプ(1970-01-01 00:00:00 UTCを起点とした経過秒数)を返す関数だ。

mysql> SET SESSION time_zone = 'UTC';
mysql> select UNIX_TIMESTAMP('1970-01-01 00:00:00');
+---------------------------------------+
| UNIX_TIMESTAMP('1970-01-01 00:00:00') |
+---------------------------------------+
|                                     0 |
+---------------------------------------+
1 row in set (0.00 sec)

ただし、2038年1月19日3時14分7秒(UTC)以降を渡すと0になってしまう。 これはドキュメントにも書いてある通り範囲外だから。

mysql> select UNIX_TIMESTAMP('2038-01-19-03-14-07');
+---------------------------------------+
| UNIX_TIMESTAMP('2038-01-19-03-14-07') |
+---------------------------------------+
|                            2147483647 |
+---------------------------------------+
1 row in set (0.04 sec)

mysql> select UNIX_TIMESTAMP('2038-01-19-03-14-08');
+---------------------------------------+
| UNIX_TIMESTAMP('2038-01-19-03-14-08') |
+---------------------------------------+
|                                     0 |
+---------------------------------------+
1 row in set (0.00 sec)

では、この境目は何かというと、32ビットで表せる符号付数値の最大値だ。

> 2 ** 31
=> 2147483648

これはMySQLに限らず、2038年問題と呼ばれているもので、 DATETIME型は'9999-12-31’までサポートしているのでこれ以降も表すことはできるが、UNIX_TIMESTAMPしても正しい値は得られなくなる。