Time::DATE_FORMATS[:default]を変更する記事たち
- 日付/時間フォーマットのデフォルトを設定 - Qiita
- Railsで表示する日付のフォーマットを変える - 動かざることバグの如し
- Rails:日時/時刻表示方法(設定)を変更する - Hello world, I am kgmx.
Railsで Time#to_s
をした場合の書式を変更する方法は「rails 時刻 フォーマット」などで調べると出てくるように、 Time::DATE_FORMATS
を独自に定義する方法がよく知られています。
しかし、いくつかの記事では Time::DATE_FORMATS[:default]
を変更しています。これはアプリケーションの動作に問題を引き起す可能性がとても高いです。
何が問題なのか
そもそも、アプリケーション全体で使用されるdefaultの値を変更する、という時点で影響範囲がとても広くなってしまうということはおわかりいただけると思います。そして、この設定値は、あなたが書くアプリケーションのコードだけではなく、そのアプリケーションが依存しているgemにも影響します。
具体例を出します。
sidekiq-cron v0.6.3 → v1.0.4 で発生する問題
あるアプリケーションで、 sidekiq-cron を使用しており、そのバージョンを v0.6.4 から v1.0.4 にアップデートすることを考えてみます。
sidekiq-cron は、CronJob が最後にenqueueされた時刻をRedisに保存します。 v0.6.4 でのコードは以下のようになっています。
#enque cron job to queue
def enque! time = Time.now.utc
@last_enqueue_time = time
ここで、 Time.now.utc
の結果は、このまま to_s
されてRedisに保存されます。
さて、 Redisから最後に queue に入った時刻を取り出す部分の v1.0.4 でのコードが以下のようになっています。
def parse_enqueue_time(timestamp)
DateTime.strptime(timestamp, LAST_ENQUEUE_TIME_FORMAT).to_time.utc
rescue ArgumentError
DateTime.strptime(timestamp, LAST_ENQUEUE_TIME_FORMAT_OLD).to_time.utc
end
そして、 LAST_ENQUEUE_TIME_FORMAT_OLD
と LAST_ENQUEUE_TIME_FORMAT
は次のようになっています。
LAST_ENQUEUE_TIME_FORMAT = '%Y-%m-%d %H:%M:%S %z'
LAST_ENQUEUE_TIME_FORMAT_OLD = '%Y-%m-%d %H:%M:%S'
この辺で勘のいい方は気づかれるかと思いますが、Redisからの last_enqueue_time
をparseする際、書式が想定外だと例外が発生します。
つまり、 Time::DATE_FORMATS[:default]
を独自定義していた場合、 sidekiq-cron v0.6.4 時代に実行されたCronJobは v1.0.4 にアップデートすると実行できずに例外が発生してしまいます。
ではどうすればいいのか
1. 都度 strftime する
デフォルトでの to_s
の結果が望ましくない場合、以下のように都度strftime
で書式を設定してやるとよいでしょう。
Time.zone.now.to_s # => "2006-01-02 15:04:05 +0900"
Time.zone.now.strftime('%Y年%m月%d日') # => "2006年01月02日"
Time.zone.now.strftime('%Y/%m/%d %A') # => "2006/01/02 Monday"
2. Time::DATE_FORMATS
に独自の書式を追加する
もしくは、Time::DATE_FORMATS[:default]
以外に独自定義した書式を登録し、それを使うようにすればよいでしょう。
Time::DATE_FORMATS[:custom] = '%Y/%m/%d %A'
Time.zone.now.to_s(:custom) # => "2006/01/02 Monday"
Time.zone.now.to_s # => "2006-01-02 15:04:05 +0900"
3. I18nの仕組みを使用する by @onk@github
https://t.co/V0XPXb6qWU ではなく? ところでコレは DATE_FORMATS 使わずに locale の ja.time.formats に足して I18n.l(now, format: :custom) じゃないかと思いました。
— Takafumi ONAKA (@onk) 2018年12月18日
Time.current. to_s(:db) は timezone 変えるので、なんとなく to_s(:foo) を単なるフォーマット用途に使うのに恐怖を覚える https://t.co/Uj6cfhcMqZ
— Takafumi ONAKA (@onk) 2018年12月18日