Date.today > Date.yesterday は必ずしも真ではなかった
Ruby on Railsの話です。
まとめ
Date.todayはRubyのDateクラスの特異メソッド- https://docs.ruby-lang.org/ja/latest/method/Date/s/today.html
- 環境変数もしくはシステムに設定されたタイムゾーンに基づいている
Date.yesterdayはRailsでDateクラスを拡張して作られたメソッド- https://api.rubyonrails.org/classes/Date.html#method-c-yesterday
- RailsというかActiveSupport
- アプリケーションに設定されたタイムゾーンに基づいている
- 参照しているタイムゾーンの設定値が異なる場合、
設定によってはDate.today == Date.yesterdayとなる時間帯が発生し得る
もうすこし詳しく
Date.today に関してはまとめに書いた以上の説明は特になし。
Date.yesterday に関して少しだけ。
# Returns a new Date representing the date 1 day ago (i.e. yesterday's date). def yesterday ::Date.current.yesterday end
Date.current に対してyesterdayを呼んでる。Date.currentはこう。
# Returns Time.zone.today when <tt>Time.zone</tt> or <tt>config.time_zone</tt> are set, otherwise just returns Date.today. def current ::Time.zone ? ::Time.zone.today : ::Date.today end
アプリケーションでタイムゾーンが設定されている場合は Time.zone.today を返す。
気づいたきっかけ
お仕事。
%m/%d のようなフォーマットで渡されるStringをDateに変換し、その日付が今日より前だった場合に特定の処理を実施する、というロジックがあった。
date_string = '01/29' # 外部から渡される(CSVファイルとか... if date_string.to_date < Date.today # do something end
対象のシステムはUTCで動いているので、この処理をJSTの1月30日00:00~08:59に実行すると Date.today は「1月29日」になる。
そのため date_string.to_date < Date.today は false になる。
これは想定した挙動ではなかった。
気づいたのはたまたま朝9時前にテストコードを実行した日があり、CIがfailしていたからだった。
テストコードでは date_string を Date.yesterday.strftime('%m/%d') で生成していた。
アプリケーションのタイムゾーンの設定はJSTになっているため、このテストをJSTの1月30日00:00~08:59に実行すると、タイムゾーンが考慮されてDate.yesterdayは1月29日になる。
気づけてラッキーだった〜。
で、こういう修正をした。
- if date_string.to_date < Date.today + if date_string.to_date < Time.zone.today # do something end
アプリケーションのタイムゾーンを考慮して「今日」を判定できるようになったのでおっけ。
ひとこと
Date.today > Date.yesterday が真とは言い切れないの、時空が歪んでいる感じがしてすごい。
おしまい。