rubocop-rails で to_time が怒られなかったので調査した
1. オプションで指定しない限り to_time は怒られない
コードレビューをしていたら
"2020-01-01 10:00".to_time
のようなコードがあり、
「そこは .in_time_zone
の方がいいですよ」とコメントしようとして、「あれ?」と思いました。
なんで「 Time.now
は Time.zone.now
にしなさい」と
いつもは怒ってくれる rubocop-rails が反応してくれていないのでしょう?
そこでドキュメントを確認すると、
Rails/Date
の AllowToTime
を false
の設定に変更しない限り、
to_time
の使用を怒ることはないとわかります。
2. to_time を使うことの問題
これは少し不思議です。
to_time
を使ってしまっては、 config.time_zone
で設定している
Railsアプリケーション側のタイムゾーンでなく、システム側(OS側)のタイムゾーンを見に行ってしまいます。
root@9f373dcf6715:/app# export TZ=America/Los_Angeles root@9f373dcf6715:/app# bundle exec rails c [1] pry(main)> Time.now => 2022-06-15 08:23:08.607609413 -0700 [2] pry(main)> Time.zone.now => Thu, 16 Jun 2022 00:23:16.122905467 JST +09:00 [3] pry(main)> "2020-06-01 10:00".to_time => 2020-06-01 10:00:00 -0700 [4] pry(main)> "2020-06-01 10:00".in_time_zone => Mon, 01 Jun 2020 10:00:00.000000000 JST +09:00 [5] pry(main)> Date.current.to_time => 2022-06-16 00:00:00 -0700 [6] pry(main)> Date.current.in_time_zone => Thu, 16 Jun 2022 00:00:00.000000000 JST +09:00
Rails/Date
の cop は、
「 Date.today
でなく Date.current
を使え」だとか、
「 Time.now
でなく Time.zone.now
を使え」だとか、
システム側のタイムゾーンでなくアプリケーション側のタイムゾーンを使うよう統一を求めるものです。
であれば、 to_time
は使うべきでないはずです。
3. 原因は DateTime にあり
ここでドキュメントに戻りましょう。
AllowToTime is true by default to prevent false positive on DateTime object.
とあります。
「DateTimeオブジェクトにおける誤検知を防ぐため」……? どういうことでしょう。
その答えはこちらの issue にあります。
https://github.com/rubocop/rubocop-rails/issues/288
要約すると、DateTimeクラスのときに、
すでにアプリケーション側のタイムゾーン情報を持つことが出来て、
そのタイムゾーン情報は to_time
しても引き継がれるから問題ないはずだ、という主張です。
[1] pry(main)> DateTime.current => Thu, 16 Jun 2022 00:50:18 +0900 [2] pry(main)> DateTime.current.to_time => 2022-06-16 00:50:23.70027614 +0900
なるほど、たしかにこのことを考えると、
to_time
メソッドの使用を必ず怒るという挙動だと、余計なおせっかいになってしまうことがありますね。
# ちなみに DateTime.now はシステム側のタイムゾーンを使ってしまう [3] pry(main)> DateTime.now => Wed, 15 Jun 2022 08:50:45 -0700 [4] pry(main)> DateTime.now.to_time => 2022-06-15 08:50:52.038531225 -0700
4. しかし DateTime は deprecated
……なのですが、2020年9月の Ruby のコミット
https://github.com/ruby/date/commit/58ca6e6a3ee20c72a77266e0f74920b12a06ee9d にて、
DateTime は deprecated(非推奨) になりました。
話の発端: https://bugs.ruby-lang.org/issues/15712
というわけなので、もう AllowToTime
は false
をデフォルトにしてもいいのではと思いまして、
issue を作っておきました。
https://github.com/rubocop/rubocop-rails/issues/715
すぐには変わらないと思うので、
ひとまずは .rubocop.yml
の設定を付け足すことで対応したいと思います。
原因がわかってスッキリしました。