はじめに:日時の表示に関してよくある問題
何も考えずにViewにcreated_at
のような日付を出力すると、「あれっ?」と思うような表示になることがあります。
<% @users.each do |user| %>
<tr>
<td><%= user.name %></td>
<!-- 作成日時を表示する -->
<td><%= user.created_at %></td>
<td><%= link_to 'Show', user %></td>
<td><%= link_to 'Edit', edit_user_path(user) %></td>
<td><%= link_to 'Destroy', user, method: :delete, data: { confirm: 'Are you sure?' } %></td>
</tr>
<% end %>
具体的には以下の2つのポイントが「あれっ?」と思う点だと思います。
- 日本時間(JST)ではなく、世界標準時(UTC)で表示されてしまう
- "Tue, 30 Jul 2019 00:12:19 +0000"のようなフォーマットは日本人にとって馴染みがない
この記事ではこの問題を解決する方法を紹介します。
タイムゾーンを日本時間に変更する
最初にタイムゾーンを日本時間にしましょう。
config/application.rb
に以下の設定を追加し、サーバーを再起動してください。
module TimeFormatSandbox
class Application < Rails::Application
# ...
# タイムゾーンを日本時間に設定
config.time_zone = 'Asia/Tokyo'
end
end
これで画面に表示された日時が日本時間になります。
日本人が読みやすい日時フォーマットにする
続いて、日時の表示形式を日本人が読みやすいフォーマットに変更しましょう。
strftimeでも変更できるが、あまりオススメできない
ネットを検索すると以下のようにstrftime
メソッドを使って検索する方法がよく出てきます。
<%= user.created_at.strftime('%Y/%m/%d %H:%M:%S') %>
もちろんこれでも目的は達成できるのですが、他にも日時を表示するViewがあると、'%Y/%m/%d %H:%M:%S'
のような書式文字列を繰り返し書かないといけないため、コードがDRYになりません。
DRYでないコードは変更に弱いコードになります。
変更に弱いコードは良くないコードです。
✅ lメソッドでDRYに書式を指定する(オススメ)
Railsにはl
メソッドという便利なメソッドがあるので、これを活用しましょう。
以下はl
メソッドの使用例です。
<!-- lメソッドを使って書式を指定する -->
<td><%= l user.created_at %></td>
ただし、l
メソッドを使うだけでは何も変化がありません。
l
メソッドを活用するには、もう少し作業が必要です。
次に行うのはロケールの設定です。
今回は日本人が読みやすい書式にするのが目的なので、アプリケーションのロケールを:ja
に設定します。
config/application.rb
に以下の設定を追加してください。
module TimeFormatSandbox
class Application < Rails::Application
# ...
# デフォルトのロケールを日本(ja)に設定
config.i18n.default_locale = :ja
end
end
続いて、config/locales/ja.yml
というファイルを作成し、以下のような設定を記述します。
ja:
time:
formats:
default: "%Y/%m/%d %H:%M:%S"
上の設定は日時(time)のデフォルトの書式を%Y/%m/%d %H:%M:%S
にするための設定です。
これでサーバーを再起動すると、日本人向けの書式で日時が表示されます。
strftime
メソッドとは異なり、l foo.created_at
のような記述でどのViewでも同じ書式が得られるため、コードもDRYになります。
応用: 複数の書式を使い分ける
「l
メソッド、便利なんだけど、この画面だけは"07/30 09:12"みたいに短く表示したいんだよな〜 」というそこのあなた!
大丈夫です。format
オプションを付けると、書式を切り替えることができます。
<!-- formatオプションを指定する -->
<td><%= l user.created_at, format: :short %></td>
上の例では:short
を指定したので、ja.yml
に対応する書式を設定します。
ja:
time:
formats:
default: "%Y/%m/%d %H:%M:%S"
short: "%m/%d %H:%M"
Tips: i18n_generatorsでja.ymlを自動生成する
上で作成したconfig/locales/ja.yml
は、i18n_generators gemを使って自動生成すると便利です。
このgemの使い方は以下のとおりです。
まず、Gemfileにi18n_generatorsを追加し、bundle install
を実行します。
group :development do
# ...
gem 'i18n_generators'
end
次にターミナルから以下のコマンドを実行します。
rails g i18n_locale ja
config/locales/ja.yml
が生成されるので、このファイルを開いてja.time.formats.default
の書式文字列を編集します。
デフォルトの書式文字列は "%Y年%m月%d日(%a) %H時%M分%S秒 %z"
になっているので、これを要件に合わせて変更してください。
なお、i18n_generatorsが生成したja.yml
には他にも日本語ロケール向けの設定がたくさん定義されています。
i18n_generatorsに関する詳しい情報はREADMEを参照してください。
Tips: View以外ではI18n.lを使う
Viewではl
と書くだけでOKですが、l
メソッドがヘルパーメソッドとして提供されていない場所(Modelなど)では、l
だけではNoMethodErrorになります。
その場合は、l
の代わりにI18n.l
と書けば、日時をフォーマットすることができます。
ちなみにl
はlocalize
のエイリアスメソッドなので、localize
と書いても構いません。
以下の記述はどれも同じ結果になります。
= l user.created_at
= I18n.l user.created_at
= localize user.created_at
= I18n.localize user.created_at
追記:Time::DATE_FORMATS[:default]を変更するのもオススメしない
日時のフォーマットを変更する方法としてもうひとつ、Time::DATE_FORMATS[:default]
の設定を変えるという方法もあるようです。
Time::DATE_FORMATS[:default] = '%Y/%m/%d %H:%M:%S'
こうすると、l
メソッドもstrftime
も使わずに書式を統一することができます。
<!-- 何もしなくても書式が'%Y/%m/%d %H:%M:%S'になる -->
<td><%= user.created_at %></td>
これだけ見ると「すごく便利じゃん!」と思うかもしれません。
ですが、アプリケーション全体のデフォルト設定が変わってしまうため、予期しない問題を引き起こすかもしれません。
実際に問題が発生する事例は以下の記事で紹介されています。
RailsのTime::DATE_FORMATS[:default]は変更しないほうがいい - Qiita
ですので、この方法もあまりオススメできません。
動画はこちら
この記事の内容はYouTube動画としてアップしています。
動画を見たい方は以下のリンクから視聴してください。