AnDeriensのブログ

個人的なブログです

2038年問題とMySQLでの対策

f:id:anderiens:20200909174610j:plain

Monoar Rahman RonyによるPixabayからの画像

概要

2038年問題というのがあるらしい。

多くのケースで、timestampが内部的には32ビットの符合付き整数で、2038年1月19日3時14分7秒(UTC)にその上限を迎える。

ja.wikipedia.org

MySQLも例外ではなくtimestamp型を使っている場合、これにハマることになるとのこと。

LaravelのIlluminate\Database\Schema\Blueprint::timestamps もtimestamp型を使ってるので、Laravel使ってる人にもふつうに影響デカそうです。

対策

対策としては

  1. Datetime型を使う
  2. 整数型を使う

という方法があるみたいです。

1. Datetime型を使う場合の注意点

DATETIME型は、タイムゾーンの影響を受けません。 そのため、タイムゾーンUTCJSTに切り替えても同じ値が入り、日付データが絶対値とならない可能性があります

https://qiita.com/juve_534/items/a9f9f72d49f8817951e8

2. 整数方を使う場合の注意点

ちなみに、2. の解決法とるときに何も考えずintとか使っても何も変わらないから気を付ける。intも32ビットの符合付き整数だから。unsigned int にすれば寿命が68年伸びます。bigintegerにすれば、人類が生きているうちは大丈夫でしょう。

ざっと計算してみると…(閏年を考慮していないので日数ずれてる)

# 検証

integer_max            = 2147483647
unsignedinteger_max    = 4294967295
biginteger_max         = 9223372036854775807
unsignedbiginteger_max = 18446744073709551615

def to_datetime(unixtime):
  r = [0] * 5
  r[0] = year   =    unixtime // (60 * 60 * 24 * 365)
  r[1] = day    = (  unixtime % (60 * 60 * 24 * 365)) // (60 * 60 * 24)
  r[2] = hour   = (( unixtime % (60 * 60 * 24 * 365)) % (60 * 60 * 24)) // (60 * 60)
  r[3] = minute = (((unixtime % (60 * 60 * 24 * 365)) % (60 * 60 * 24)) % (60 * 60)) // 60
  r[4] = second = (((unixtime % (60 * 60 * 24 * 365)) % (60 * 60 * 24)) % (60 * 60)) % 60

  return tuple(r)

print('interger: %d年%d日%d時%d分%d秒' % to_datetime(integer_max))
print('unsignedinterger: %d年%d日%d時%d分%d秒' % to_datetime(unsignedinteger_max))
print('biginterger: %d年%d日%d時%d分%d秒' % to_datetime(biginteger_max))
print('unsignedbiginterger: %d年%d日%d時%d分%d秒' % to_datetime(unsignedbiginteger_max))

結果

interger: 68年35日3時14分7秒
unsignedinterger: 136年70日6時28分15秒
biginterger: 292471208677年195日15時30分7秒
unsignedbiginterger: 584942417355年26日7時0分15秒

参考記事

MySQLで timestamp型 を使うのはNG!2038年問題の対処法 | PisukeCode - Web開発まとめ

MySQLのtimestamp型に起きる2038年問題 - Qiita

広告