タイムゾーンの指定漏れをRuboCopで検知する

こんにちは、YOUTRUSTのしぶしゅん(YOUTRUST/X)です。

Railsのプログラムを書く上で注意するべきことにタイムゾーンの指定があります。 Timeに関するメソッドはTime.currentやTime.atなどRubyRailsに多くあります。各メソッドで明示的にタイムゾーンを指定するか、指定しない場合は実行環境に結果が依存するなど挙動が異なります。

タイムゾーンを指定していないコードを書くと、実行時刻によっては日付がずれてしまうことがあります。想定と違った挙動は不具合の原因になります。 この記事ではタイムゾーンを指定していないコードの不具合の例と、タイムゾーンの指定漏れをRuboCopで検知する設定を紹介します。

タイムゾーンを指定していないコードの不具合の例

module Helpers
  module TimeHelpers
    def format_unix_timestamp_to_date(timestamp)
      Time.at(timestamp).strftime('%Y/%m/%d')
    end
  end
end

実際にあった例を紹介します。RSpecの中で使用するタイムスタンプから日付に変換するヘルパーメソッドを定義しました。このコードはタイムゾーンを指定していませんでした。

ヘルパーメソッドを検証するテストを書いてみます。

RSpec.describe 'TimeHelpers' do
  describe '#format_unix_timestamp_to_date' do
    context '日本時間の午前1時に実行したとき' do
      let(:timestamp) { Time.zone.local(2023, 11, 1, 1, 0, 0).to_i }

      it '正しい日付が返る' do
        expect(format_unix_timestamp_to_date(timestamp)).to eq('2023/11/01')
      end
    end

    context '日本時間の午前10時に実行したとき' do
      let(:timestamp) { Time.zone.local(2023, 11, 1, 10, 0, 0).to_i }

      it '正しい日付が返る' do
        expect(format_unix_timestamp_to_date(timestamp)).to eq('2023/11/01')
      end
    end
  end
end

午前1時と午前10時から日付に変換するテストを実行する場合、午前1時のテストが失敗します。 タイムスタンプから日付に変換する際にJSTは+9時間のため、午前1時はUTCの前日の16時となり前日の日付になってしまいます。

Failures:

  1) TimeHelpers #format_unix_timestamp_to_date 日本時間の午前1時に実行したとき 正しい日付が返る
     Failure/Error: expect(format_unix_timestamp_to_date(timestamp)).to eq('2023/11/01')

       expected: "2023/11/01"
            got: "2023/10/31"

       (compared using ==)

タイムゾーンを指定するために次のように変更しました。

  • 変更前: Time.at(timestamp).strftime('%Y/%m/%d')

  • 変更後: Time.zone.at(timestamp).strftime('%Y/%m/%d')

この変更により午前1時と午前10時に実行するテストが両方成功するようになります。

タイムゾーンの指定漏れをRuboCopで検知する設定

今回は気づくことができましたが、次回も気づくとは限りません。 仕組みで防ぐため、RuboCopでタイムゾーンの指定漏れを検知する設定を有効化しました。

有効化した設定と設定例になります。 Class: RuboCop::Cop::Rails::TimeZone — Documentation for rubocop-rails (2.22.1)

Gemfile

gem 'rubocop-rails', require: false

.rubocop.yml

require:
  - rubocop-rails

# Rails/TimeZoneだけを有効化する
Rails:
  Enabled: false
Rails/TimeZone:
  Enabled: true

この設定でタイムゾーンを指定していないコードを記述するとRuboCopが検知してくれるようになりました。

また既存コードに含まれるタイムゾーン指定漏れ箇所を検知することができるようになりました。 何箇所かあったため、確認した上で修正を行いました。

まとめ

タイムゾーンを指定していないコードをRuboCopで防ぎ、コードの品質を高めることができました。 今回の取り組みを通じてRuboCop設定について興味が出たため、今後もプロジェクトの状況に合わせて検討し導入していきたいと思います。

また、YOUTRUSTはエンジニア採用を積極的に進めております!ぜひご覧ください!

career.youtrust.co.jp