Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
5
Help us understand the problem. What is going on with this article?
@yu_suke1994

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

More than 1 year has passed since last update.

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

参考

5
Help us understand the problem. What is going on with this article?
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
yu_suke1994
帰って寝たい

Comments

No comments
Sign up for free and join this conversation.
Sign Up
If you already have a Qiita account Login
5
Help us understand the problem. What is going on with this article?