Railsユーザーなのに、まだstrftime使っているの?と思っていたら Rails の DATE_FORMATS でハマった話

TL;DR

  • strftime はクソ
  • DATE_FORMATSは型ごとに設定する必要がある
  • DATETIME型のデータは Time::DATE_FORMATS[:ymd] = ("%Y年%m月%d日")
  • DATE型のデータは Date::DATE_FORMATS[:ymd] = ("%Y年%m月%d日")

前提

以下、今日(2016年10月23日)作成されたユーザーの作成時間(user.created_at、DATETIME型)を整形するという流れで進めます。

strftime を使う場合

日付のデータをフォーマットするときは、 strftime 関数を使います。

user.created_at.strftime("%Y年%m月%d日") 
# => 2016年10月23日

ただ strftime を使ってしまうと都度フォーマットを設定するため、日付フォーマットがバラけてしまいます。 (rails date format などで検索すると上位に表示される方法なので注意しましょう。)

そこで 以下の方法を使います。

time_formats を使う

まず config/initializers/time_formatsに フォーマットを指定します。

# config/initializers/time_formats.rb

Time::DATE_FORMATS[:ymd] = ("%Y年%m月%d日") 

その後、

user.created_at.to_s(:ymd)
# => 2016年10月23日

とするとフォーマットがinitializers/time_formats.rbに集約されていい感じになります。

仮にユーザーの誕生日をフォーマットしたいとします。
誕生日は user.birthday(DATE型) に格納されています。

user.created_at のときに作ったフォーマットを使いまわして整形しようとすると・・・

user.birthday.to_s(:ymd)
# => 2016-10-23

フォーマットされていない・・・?

解決方法

原因は、 initializer の設定ミスでした。

先程設定した Time::DATE_FORMATS[:ymd] = ("%Y年%m月%d日")Time はdatetime型のみ有効です。

そこで、DATE型も有効化されるように追記します。

# config/initializers/time_formats.rb

Time::DATE_FORMATS[:ymd] = ("%Y年%m月%d日") 
Date::DATE_FORMATS[:ymd] = ("%Y年%m月%d日") 

この状態で再度 user.birthday をフォーマットすると

user.birthday.to_s(:ymd)
# => 2016年10月23日

無事できました。

所感

初見だとわかりにくいところだなと感じました。 30分くらいハマっていたのでメモしておきます。

WEBのことならなんでも聞いてください。↓

twitter.com