※ 結論だけ知りたいという人は解決法から見てください
「まだRailsでstrftime使ってるやついる?」
「いねえよなぁ!!?」
...
...
はい、使ってます。
strftimeを使用して、日時をフォーマットする際
<p class="time"><%= @model.time.strftime('%Y年%m月%d日 %H時%M分') %></p>
のように毎回記述する必要があり
「いちいち指定しなくても同じ形式でフォーマットしてほしい」
「フォーマットをまとめて管理したい」
といった悩みに苦しめられてきました。
「仕方ない」と諦めていたこの悩み...解決する方法を実は見つけてしまったのです。
私みたいに諦めてstrftimeを使っているそこの貴方、今まさにstrftimeを使おうとしているそこの貴方。
「もっと早く気づいていれば、もっといい感じにプロダクトを作れた」
と思うその前に、是非参考にしてみてください。
strftimeとは?
strftimeは、日時のデータを指定したフォーマット文字列に変換できるメソッドです。
詳しい使い方はRubyリファレンスマニュアルを参照してください。
strftimeを使いたくない理由
日時のフォーマットで検索するとよく出てくるstrftimeですが、 使用する時には
@model.time.strftime('%Y年%m月%d日 %H時%M分')
のような記述を繰り返し記述する必要があります。
全て%Y年%m月%d日 %H時%M分のフォーマットで表示したいだけにも関わらず、同じ内容を繰り返し書くことになるので、コードがDRYな状態とは言えません。
「日時の表示を別の形式に変えて欲しい!」
といった急な要望が来た時
- 修正に時間がかかる
- 一部修正が漏れていた
といった問題が起きやすくなります。
解決法
ja.ymlにフォーマットを記述して、lメソッドを使って呼び出す
今回の問題は、これだけで解決します。
具体的な設定方法をこれから説明します。
デフォルトのlocaleをjaに設定
railsはconfig/localesというフォルダの中で翻訳したい各国語の文言を管理しています。localeは元々、多言語化用に使われるものでした。多言語化以外にも、バリデーションの文言を管理したり、各カラムの日本語名を管理したりと、用途は多岐に渡っています。
今回は、config/application.rbでデフォルトの言語を:ja(日本語)に指定します。
この設定を入れることで、config/locales/ja.ymlの中で言語を管理するようになります。
デフォルト言語を:jaに設定して、ja.ymlで言語管理していくことは定番の方法なので、覚えておきましょう。
config.i18n.default_locale = :ja
ja.ymlに指定したいフォーマットを記述
config/locales/ja.ymlに指定したいフォーマットを記述します。ja.ymlがない場合は、作成してください。
ja:
date:
formats:
default: '%Y/%-m/%-d'
time:
formats:
default: '%Y-%-m-%-d %H:%M:%S'
Date型のフォーマットは、date:以下に指定したものが使用されます。
Time、DateTime、TimeWithZone型のフォーマットは、time:以下に指定したものが使用されます。
Date型に対してtime:のフォーマットは利用できず、エラーになります。逆も同様です。両方とも設定することをオススメします。
default:に指定したフォーマットが標準になります。ご自身のアプリケーションの中で一番使われているフォーマットを指定してください。
lメソッドを使用して、フォーマットを反映する
lメソッドは、I18nモジュールに用意されているlocalizeメソッドのエイリアスで、日付や数値などをlocaleに指定されているフォーマットに変換します。
<%= l @model.time %> <%#=> 2022-06-10 16:30:40 %>
ViewやControllerでは、lメソッドがヘルパーメソッドとして用意されているので、lだけで呼び出すことができます。
それ以外の場所では、I18n.lで呼び出してください。
# Date
I18n.l(Date.today) #=> '2022/6/10'
# Date
I18n.l(Time.current.to_date) #=> '2022/6/13'
# Datetime
I18n.l(DateTime.now) #=> '2022-6-10 16:30:40'
# Time
I18n.l(Time.now) #=> '2022-6-10 16:30:40'
# TimeWithZone
I18n.l(Time.current) #=> '2022-6-10 16:30:40'
# ヘルパーが用意されていないところでlで呼び出すと、NoMethodErrorになる
l(Time.current) #=> NoMethodError (undefined method `l' ...
lメソッドを使うことで、strftimeで必要だったフォーマット指定が必要なくなります。
応用: default以外のフォーマットを指定する
運用していく中で、日時の表示方法は一つとは限りません。
「このページは年の表示要らない」「このページだけ日本語で月とか日って表示したい」
といった時、default以外のフォーマットを作成し、フォーマットを切り替えることが可能です。
ja:
date:
formats:
default: '%Y/%-m/%-d'
long: '%Y年%-m月%-d日(%a)'
abbr_day_names: [日, 月, 火, 水, 木, 金, 土]
time:
formats:
default: '%Y-%-m-%-d %H:%M:%S'
short: '%m-%d %H:%M'
<%= l @model.time, format: :short %> <%#=> 06-10 16:30 %>
I18n.l(Date.today, format: :long) #=> '2022年6月10日(金)'
I18n.l(Time.current, format: :short) #=> '06-10 16:30'
# Date型にtimeでしか指定していないフォーマットを使うとエラーになる
I18n.l(Date.today, format: :short) #=> I18n::MissingTranslationData (translation missing: ja.date.formats.short)
# TimeWithZone型にdateでしか指定していないフォーマットを使うとエラーになる
I18n.l(Time.current, format: :long) #=> I18n::MissingTranslationData (translation missing: ja.time.formats.long)
まとめ
strftimeだけを用いて都度日時のフォーマットをしていくと、コードがDRYな状態ではなくなっていきます。
- 対象の
localeのymlに指定したいフォーマットを記述 -
lメソッドを用いてView表示する
この2つのことをするだけで、日時のフォーマットをまとめて管理でき、よりDRYなコードに近づきます。
たくさんのstrftime修正に悩まされるその前に、是非今回の方法を試してみてください。