更新日:
【Rails】 strftimeの使い方と扱えるクラスについて
strftimeとは、日時データを指定したフォーマットで文字列に変換することができるメソッドです。
1
2
3
4
5
6
7
8
9
blog = Blog.find(1)
# 通常の出力結果
blog.created_at
=> Fri, 26 Jul 2019 12:00:00 UTC +00:00
# strftimeメソッドを使い指定した形で文字列として出力
blog.created_at.strftime("%Y年%m月%d日")
=> "2019年07月26日"
TimeクラスとDateクラス、DateTimeクラスのオブジェクトを指定したフォームで文字列として取得し表示させることができるのがstrftime
メソッドです。
strftimeが扱えるクラス
strftime
メソッドはTimeクラス
とDateクラス
、DateTimeクラス
のオブジェクトに対して使うことができます。
それぞれのクラスの特徴を確認しましょう。
Timeクラスとは
日時を扱えるクラスです。
このクラスのインスタンスは下記のように取得することができます。
1
2
3
4
5
6
7
# 現在の日時を取得
today = Time.now
=> 2020-01-01 12:00:00 +0900
# 日時を指定して作成
day = Time.new(2020,1,1,12,00,00)
=> 2020-01-01 12:00:00 +0900
Dateクラスとは
日付を扱えるクラスです。
このクラスのインスタンスは下記のように取得することができます。
rubyで使うにはrequire "date"
が必要です。
1
2
3
4
5
6
7
8
9
require "date"
# 現在の日付を取得
today = Date.today
=> Wed, 01 Jan 2020
# 日付を指定して作成
day = Date.new(2020, 1, 1)
=> Wed, 01 Jan 2020
DateTimeクラスとは
日時を扱えるクラスです。
DateTimeクラスはDateクラスのサブクラスとして定義されています。
ですのでrubyで使うにはDateクラスと同じようにrequire "date"
が必要です。
1
2
3
4
5
6
7
8
9
require "date"
# 現在の日時を取得
today = DateTime.now
=> Wed, 01 Jan 2020 12:00:00 +0000
# 日時を指定して作成
day = DateTime.new(2020,1,30,12,00,30)
=> Wed, 01 Jan 2020 12:00:00 +0000
このようにして日時や日付を取得できますが、このままだと2020-01-01 12:00:00 +0900
やWed, 01 Jan 2020
の形式でしか出力されません。
これを2019年1月1日
や2019/1/1
など指定したフォームで表示させたいときにstrftime
メソッドを使います。
strftimeメソッドの使い方
strftime
メソッドは下記のように使用します。
1
2
datetime = DateTime.now
datetime.strftime("書式")
例えば2019年01月01日
と表示させたい時は下記のように記述します。
1
2
datetime.strftime("%Y年%m月%d日")
=> "2019年01月01日"
指定できる書式を確認しよう
指定できる書式は下記のものがあり、それぞれを組み合わせて使うことも可能です。
個別に取得
※元データは2019-01-01T12:00:00+09:00
を使用
書式 | 返り値 | 説明 |
---|---|---|
%Y | 2019 | 西暦を4桁の数で取得する※西暦1年は「0001」 |
%m | 01 | 月を必ず2桁の数字で取得する(01-12) |
%-m | 1 | 月を1桁か2桁の数字で取得する(1-12) |
%d | 01 | 日付を必ず2桁で取得する(01, 02 ... ) |
%-d | 1 | 日付を1桁か2桁で取得する(1, 2 ... 10, 11 ...) |
%H | 12 | 24時間制の時刻を必ず2桁で取得する(00-23) |
%-H | 12 | 24時間制の時刻を1桁か2桁で取得する(0-23) |
%I | 12 | 12時間制の時刻を1桁か2桁で取得する(1-12) |
%M | 00 | 分を取得する(00-59) |
%S | 00 | 秒を取得する(00-60)※60はうるう秒 |
これを使った例を見てみましょう。
1
2
3
4
5
6
date = DateTime.new(2020,1,30,12,00,30)
p date
=> #<DateTime: 2020-01-30T12:00:30+00:00>
p date.strftime("%m月%d日")
=> "01月30日"
このように自分が指定した初期で文字列として取得することができました。
まとめて取得
※元データは2019-01-01T12:00:00+09:00
を使用
書式 | 返り値 | 説明 |
---|---|---|
%c | Tue Jan 01 12:00:00 2019 | 日付と時刻を省略名で取得する(Sun Jan 01 12:00:00 2019) |
%D | 01/01/19 | 日付を「01/12/19」の形式で取得する※「日/時/年」の順 |
%F | 2019-01-01 | 日付を「2019-07-26」の形式で取得する |
%R | 12:00 | 時刻を「12:00」の形式で取得する |
%r | 12:00:00 PM | 時刻を「12:00:00 PM」の形式で取得する |
%T | 12:00:00 | 時刻を「12:00:00」の形式で取得する |
%v | 1-Jan-2019 | 日付を「1-Jan-2019」の形で取得する※「日/時/年」の順 |
%X | 12:00:00 | 時刻を「12:00:00」の形式で取得する |
%x | 01/01/19 | 日付を「01/12/19」の形式で取得する※「日/時/年」の順 |
その他の書式
※元データは2019-01-01T12:00:00+09:00
を使用
書式 | 返り値 | 説明 |
---|---|---|
%A | Tuesday | 曜日の名称をフルで取得する(Sunday, Monday ... ) |
%a | Tue | 曜日の省略名を取得する(Sun, Mon ... ) |
%B | January | 月の名称をフルで取得する(January, February ... ) |
%b | Jan | 月の省略名を取得する(Jan, Feb ... ) |
%C | 20 | 世紀を数字で取得する(00, 01 ...)※2020年だと20 |
%h | Jan | 月の省略名を取得する(Jan, Feb ... ) |
%L | 000 | ミリ秒(ms)を取得する(000-999) |
%j | 001 | 1月1日からの通算日を取得する(001-366) |
%N | 000000000 | 秒の小数点以下を9桁で取得する※「%6N」で6桁など指定可能 |
%P | pm | 午前か午後を小文字で取得する(am, pm) |
%p | PM | 午前か午後を大文字で取得する(AM, PM) |
%s | 1546344000 | 1970-01-01 00:00:00 UTC から経過した秒を取得する |
%U | 00 | 1 年の週の数を取得する (00-53)※最初の日曜日が第1週の始まり |
%u | 2 | 曜日を表す数を取得する(1-7)※1が月曜日, 2が火曜日 ... |
%V | 01 | ISO 8601形式の週の数を取得する(01-53) |
%W | 00 | 1 年の週の数を取得する (00-53)※最初の月曜日が第1週の始まり |
%w | 2 | 曜日を表す数を取得する(0-6)※0が日曜日, 1が月曜日 ... |
%Z | +09:00 | タイムゾーン(世界標準時間と設定した国の時間の時差)を表示する(+09:00) |
%z | +0900 | タイムゾーン(世界標準時間と設定した国の時間の時差)を表示する(+0900) |
実際に使ってみよう
それではrailsで実際に使ってみましょう。
strftimeはTime型やDate型、DateTime型に使うので、保存する時にはそれぞれの型を指定する必要があります。
その為、マイグレーションファイルでtime型
やdate型
、datetime型
でカラムを作成します。
railsだとテーブルを作成する際のマイグレーションファイルにデフォルトでt.timestamps
という記述があり、自動でcreated_atカラム
とupdated_atカラム
がdatetime型カラム
として作成されます。
1
2
3
4
5
6
t.time :カラム名
t.date :カラム名
t.datetime :カラム名
# created_atカラムとupdated_atカラムをdatetime型で自動で作成
t.timestamps
そして、コントローラーやモデルでインスタンスを取得します。
1
2
3
def show
@message = Message.find(params[:id])
end
ビューで日時を表示させます。
2019年01月11日14時15分
と表示させたい時は下記のように記述します。
1
<%= @message.created_at.strftime("%Y年%m月%d日%H時%M分") %>
ただこれだとコードが長くなるのでメソッド化するのが一般的です。
ビューで使うメソッドはモデルに記述しましょう。
1
2
3
def set_date
created_at.strftime("%Y年%m月%d日%H時%M分")
end
ビューで使うときは下記のように記述します。
1
<%= @message.set_date %>
だいぶスッキリしましたね!
曜日を日本語で表示させてみよう
用意されている書式の中には日本語表記のものがありません。
曜日などは、日本語で表示したいですね。
ではどういった方法があるでしょうか。
この時に使う書式は%w
です。これは曜日を表す数を取得する書式です。
0から6までの数字が取得でき、日曜日が0
、月曜日が1
といった感じで取得できます。
勘のいい方ならもうわかりますね。
そうです、配列を作ってあげてそこから取得できる数字を使って日本語の曜日名を取得すればいいですね。
ただこの返り値は文字列としての数字なので、to_iメソッドを使って数値オブジェクトに変換する必要があります。
下記のようなコードになります。
1
2
3
4
weeks = ["日","月","火","水","木","金","土"]
num = @message.created_at.strftime("%w").to_i
week = weeks[num]
=> "日"
これでweekという変数に日本語の曜日名が入りました。
またはwdayメソッド使っても同じことができます。
wdayメソッド
Timeクラス、Dateクラス、DataTimeクラスのオブジェクトに使用すると曜日を0
(日曜日)から6
(土曜日)の整数で取得できるメソッドです。
このメソッドを使うと下記のように書くこともできます。
1
2
3
4
weeks = ["日","月","火","水","木","金","土"]
week = weeks[@message.created_at.wday]
# @message.created_at.wdayで日曜日なら数字として0を取得
=> "日"
配列は%記法を使うともっと短く書くことができます。
1
2
week = %w(日 月 火 水 木 金 土)[@message.created_at.wday]
=> "日"
ビューで表示させるには下記のように記述します。
1
<%= @message.created_at.strftime("%Y年%m月%d日%H時%M分#{week}曜日") %>
time_formatsを使ってみよう
TimeクラスやDateクラス、DateTimeクラスのオブジェクトに対してto_sメソッド
を使うと日時を文字列として取得することができます。
デフォルトだと下記の形で取得できます。
1
2
3
datetime = DateTime.now
datetime.to_s
=> "2019-01-10T12:00:00+09:00"
この形を変えるためstrftime
メソッドを使っていました。
time_formats
を使うとstrftimeメソッドを使わなくてもto_s
メソッドで取得できる形式を指定することができます。
time_formats.rbを作成しよう
それでは設定の流れを確認していきましょう。
まずはconfig/initializersフォルダ内
にtime_formats.rb
を作成します。
このファイルに下記のように定義します。
1
クラス名::DATE_FORMATS[:名前] = "書式"
[:名前]
とするとto_s(:名前)
の形で指定した形式で取得することができます。
この部分は好きな名前をつけることができます。
いくつでも指定が可能です。
定義できるのはTimeクラス
とDateクラス
です。
Timeクラスの例
それではTimeクラスの書き方を例をみてみましょう。
1
2
3
4
# Timeクラスの定義
Time::DATE_FORMATS[:date] = "%m/%d"
Time::DATE_FORMATS[:yeardate] = "%Y年%m月%d日"
Time::DATE_FORMATS[:datetime] = "%Y年%m月%d日 %H時%M分"
railsのcreated_at
やupdated_at
で取得できるクラスはActiveSupport::TimeWithZoneクラス
です。Time::DATE_FORMATS
の接頭辞のTime
がActiveSupport::TimeWithZoneクラスに呼応していています。
上のように定義すると下記のように使うことができます。
1
2
3
4
5
6
7
8
9
10
11
12
13
blog = Blog.find(1)
blog.created_at
=> Wed, 01 Jan 2020 12:00:00 UTC +00:00
blog.created_at.to_s(:date)
=> "01/01"
blog.created_at.to_s(:yeardate)
=> "2020年01月01日"
blog.created_at.to_s(:datetime)
=> "2020年01月01日 12時00分"
Dateクラスの例
次にDateクラスの書き方を例をみてみましょう。
1
2
3
# Dateクラスの定義
Date::DATE_FORMATS[:date] = "%m月%d日"
Date::DATE_FORMATS[:yeardate] = "%Y年%m月%d日"
Date::DATE_FORMATS
の接頭辞のDate
がDateクラスに呼応していています。
上のように定義すると下記のように使うことができます。
1
2
3
4
5
6
7
day = Date.today
day.to_s(:date)
=> "01月01日"
day.to_s(:yeardate)
=> "2020年01月01日"
DateTimeクラスの場合
DateTimeクラスはDateTime::DATE_FORMATS
ではなくTime::DATE_FORMATS
が適用されます。
1
2
3
4
# Timeクラスの定義
Time::DATE_FORMATS[:date] = "%m/%d"
Time::DATE_FORMATS[:yeardate] = "%Y年%m月%d日"
Time::DATE_FORMATS[:datetime] = "%Y年%m月%d日 %H時%M分"
上のように定義した場合、DateTimeはTimeクラスが適用されるか確認してみます。
1
2
3
4
5
6
7
day = DateTime.now
day.to_s(:date)
=> "01月01日"
day.to_s(:yeardate)
=> "2020年01月01日"
もしtime_formats.rb
にDateTimeクラスで定義するとDate型として定義されます。
1
2
Time::DATE_FORMATS[:date] = "%m/%d"
DateTime::DATE_FORMATS[:date] = "%m月%d日"
上のように定義した場合の結果を確認してみましょう。
1
2
3
4
5
6
7
8
9
10
11
day = DateTime.now
# Time型が適用される
day.to_s(:date)
=> "01/01"
today = Date.today
# Date型として定義される
today.to_s(:date)
=> "01月01日"
このようにDateTime::DATE_FORMATS
として定義するとDate::DATE_FORMATS
として定義されてしまいます。
ですのでDate::DATE_FORMATS
を定義した後にDateTime::DATE_FORMATS
を定義すると、その前に定義したDate::DATE_FORMATS
が上書きされてしまうので注意しましょう。
1
2
3
# 下記のように記述するとDate型のコードが上書きされる
Date::DATE_FORMATS[:date] = "%m月%d日"
DateTime::DATE_FORMATS[:date] = "%m/%d"
上のように定義した場合の結果を確認してみましょう。
1
2
3
4
5
day = Date.today
day.to_s(:date)
=> "01/01"
# Date型が上書きされDateTime型で定義した結果が表示される
このようにDateTime型を定義したためDate型の定義が上書きされてしまいます。
DateTime型を定義をするといろいろややこしくなるのでしないようにしましょう。
time_formatsのメリット
strftime
メソッドの場合は毎回指定しないと行けなかったり、dateの記述を人によって
%y/%m/%d
だったり%y年%m月%d日
にしたりとか偏りが出て統一が難しいというデメリットがあったりします。
ですがtime_formatsを使って日付や時刻の表示をあらかじめ決めておけば、複数人でアプリを開発しているときにでも表示形式を一貫させることができます。
またtime_formatsを使うとこのように短く直感的に記述することができます。
1
2
3
4
5
blog.created_at.strftime("%Y年%m月%d日 %H時%M分")
=> "2020年01月01日 12時00分"
blog.created_at.to_s(:datetime)
=> "2020年01月01日 12時00分"
上のように比較してみるとtime_formatsを使ったほうがコードがスッキリしていて、datetime
という名前なので日時を表示できるなと推測でき、コードの可読性も上がることがわかります。
また下記のように名前の部分をdefault
とするとto_sメソッド
のみで使ったときの結果を変えることができます。
1
Time::DATE_FORMATS[:default] = "%Y年%m月%d日"
上のように定義するとto_sメソッド
のみで取得ができます。
1
2
3
4
5
6
7
8
9
blog = Blog.find(1)
# :defaultで変更している場合の結果
blog.created_at.to_s
=> "2020年01月01日"
# 変更前の結果
blog.created_at.to_s
=> "2020-01-01 12:00:00 +0900"
ですが、defaultを変更してしまうとアプリケーション全体に影響が及んでしまい、インストールしているgemにも影響を与えて、アプリケーションによってはエラーが起こる危険性があるので変更するのはあまりおすすめしません。
この記事のまとめ
- strftimeメソッドは日時データを指定したフォーマットで文字列に変換することができるメソッド
- Timeクラス、Dateクラス、DateTimeクラスに使うことが出来る
- time_formatsを使うとより簡単に変換することが出来る