6
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

「まだRailsでstrftime使ってるやついる?」「いねえよなぁ!!?」【日時のフォーマットをja.ymlで管理する】

Last updated at Posted at 2022-06-16

※ 結論だけ知りたいという人は解決法から見てください

「まだRailsでstrftime使ってるやついる?」

「いねえよなぁ!!?」

...
...

はい、使ってます。

strftimeを使用して、日時をフォーマットする際

View
<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/application.rb
config.i18n.default_locale = :ja

ja.ymlに指定したいフォーマットを記述

config/locales/ja.ymlに指定したいフォーマットを記述します。ja.ymlがない場合は、作成してください。

config/locales/ja.yml
ja:
  date:
    formats:
      default: '%Y/%-m/%-d'
  time:
    formats:
      default: '%Y-%-m-%-d %H:%M:%S'

Date型のフォーマットは、date:以下に指定したものが使用されます。
TimeDateTimeTimeWithZone型のフォーマットは、time:以下に指定したものが使用されます。
Date型に対してtime:のフォーマットは利用できず、エラーになります。逆も同様です。両方とも設定することをオススメします。
default:に指定したフォーマットが標準になります。ご自身のアプリケーションの中で一番使われているフォーマットを指定してください。

lメソッドを使用して、フォーマットを反映する

lメソッドは、I18nモジュールに用意されているlocalizeメソッドのエイリアスで、日付や数値などをlocaleに指定されているフォーマットに変換します。

View
<%= l @model.time %> <%#=> 2022-06-10 16:30:40 %>

ViewやControllerでは、lメソッドがヘルパーメソッドとして用意されているので、lだけで呼び出すことができます。
それ以外の場所では、I18n.lで呼び出してください。

Model
# 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以外のフォーマットを作成し、フォーマットを切り替えることが可能です。

config/locales/ja.yml
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'
View
<%= l @model.time, format: :short %> <%#=> 06-10 16:30 %>
Ruby
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修正に悩まされるその前に、是非今回の方法を試してみてください。

6
3
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?