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分くらいハマっていたのでメモしておきます。