MySQL4環境でSequelからTIMESTAMPがそのまま取得できない問題を解決した
2023-09-06
はじめに
モバイルエンジニアのはずでしたが最近は Rails を触っています。業務でSequelを使って MySQL4 に保存されている TIMESTAMP を取得しようとしたのですがどうやっても nil しか返ってきませんでした。MySQL5 だと普通に取得できるのになぜ?となって色々調べてようやく動くようになったのでその時の話です。
結論としては、TIMESTAMP を String として取り出しその後変換して使いました。
解決方法
当初は(かなり省略した書き方ですが)このような書き方になっていました。
where(hoge: fuga)
.select(:time_stamp)
まずは DB のレコードがないのかと思ったのですがきちんと入っていました。次に Sequel の書き方が間違っており発行された SQL がおかしいのかと思いました。が、実際に発行された SQL をログから見つけ、実行しても普通に動いていました。
ここまで調べてようやく DB から Ruby(Model) に持ってくる時になにかおかしなことになっている?と気付きました。
ChatGPT 君に MySQL5 と MySQL4 で TIMESTAMP の扱いになにか違いがあるか聞いたところ、以下のような回答が返ってきました(他にもあったのですがここでは今回の内容と関係がある箇所のみを書いています)。
MySQL4 では TIMESTAMP にタイムゾーンを含んでいない
さらに踏み込んで聞いたら Sequel で取りたければ文字列として取得後、変換するのがいいよと教えてくれたので実際に試したところ取得できるようになりました。nil になる原因としては UTC を含んでいないため Ruby の Time オブジェクトに変換できてないんだろうな〜と思っています。ChatGPT も MySQL4.1 以降から UTC を含むようになったと言っていたのでこれが原因で MySQL5 では動いていたようでした。
where(hoge: fuga)
.select(Sequel.lit("DATE_FORMAT(`time_stamp`, '%Y-%m-%d %H:%i:%s')")
Sequel.litを使うと String として取得できるっぽいです。
自分の場合は DATE 型で欲しかったので、Sequel.cast
を使って DATE に変換して Model 上から扱えるようにしました。
最後に
業務で Vue を使ったフロントエンド開発をしている時も日付とブラウザの相性で結構詰まったりしてまた日付か…と悩みましたが、なんとか解決できました。Sequel と MySQL4 という極めて珍しい組み合わせではありますがまた知識を深めることができました。
あと TIMESTAMP には 2038 年問題というものがあり、できれば DATETIME がいいというのも見たりして、そういう問題もあるんだな〜と勉強になりました。世の中知らないことだらけだな〜。