12
6

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

RailsのTime::DATE_FORMATS[:default]は変更しないほうがいい

Last updated at Posted at 2018-11-21

Time::DATE_FORMATS[:default]を変更する記事たち

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 でのコードは以下のようになっています。

lib/sidekiq/cron/job.rb
#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 でのコードが以下のようになっています。

lib/sidekiq/cron/job.rb
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_OLDLAST_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

参考

12
6
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
12
6

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?