すでにメンバーの場合は

無料会員登録

GitHubアカウントで登録 Pikawakaが許可なくTwitterやFacebookに投稿することはありません。

登録がまだの方はこちらから

Pikawakaにログイン

GitHubアカウントでログイン Pikawakaが許可なくTwitterやFacebookに投稿することはありません。

Rails

【Rails】 strftimeの使い方と扱えるクラスについて

ぴっかちゃん
ぴっかちゃん

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クラスとは

日時を扱えるクラスです。
このクラスのインスタンスは下記のように取得することができます。

ターミナル | 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"が必要です。

ターミナル | 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"が必要です。

ターミナル | DateTimeクラスの説明
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 +0900Wed, 01 Jan 2020の形式でしか出力されません。

これを2019年1月1日2019/1/1など指定したフォームで表示させたいときにstrftimeメソッドを使います。

strftimeメソッドの使い方

strftimeメソッドは下記のように使用します。

strftimeメソッドの使い方
1
2
datetime = DateTime.now
datetime.strftime("書式")

例えば2019年01月01日と表示させたい時は下記のように記述します。

ターミナル | strftimeの使い方
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はうるう秒

これを使った例を見てみましょう。

ターミナル | strftimeの例
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分") %>

2019年1月11日14時15分

ただこれだとコードが長くなるのでメソッド化するのが一般的です。
ビューで使うメソッドはモデルに記述しましょう。

モデル
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(土曜日)の整数で取得できるメソッドです。
このメソッドを使うと下記のように書くこともできます。

ターミナル | wdayメソッドの使い方
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}曜日") %>
%記法(パーセント記法)

コードをシンプルに記述することができる記法です。%iはシンボルの配列を作り出し、%wは文字列の配列を作り出すことができます。

記述するコードが減るので、可読性が上がったりタイプミスによるエラーが出る確率を減らすことができます。このようなRubyの基礎から徹底的に学びたい方は、チェリー本と呼ばれるこちらの参考書が役に立ちます!

time_formatsを使ってみよう

TimeクラスやDateクラス、DateTimeクラスのオブジェクトに対してto_sメソッドを使うと日時を文字列として取得することができます。
デフォルトだと下記の形で取得できます。

ターミナル | 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を作成します。

このファイルに下記のように定義します。

time_formats.rb | 定義の仕方
1
クラス名::DATE_FORMATS[:名前] = "書式"

[:名前]とするとto_s(:名前)の形で指定した形式で取得することができます。
この部分は好きな名前をつけることができます。
いくつでも指定が可能です。

定義できるのはTimeクラスDateクラスです。

Timeクラスの例

それではTimeクラスの書き方を例をみてみましょう。

time_formats.rb | 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_atupdated_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クラスの書き方を例をみてみましょう。

time_formats.rb | 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が適用されます。

time_formats.rb | DateTimeクラスは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分"

上のように定義した場合、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型として定義されます。

time_formats.rb | DateTimeクラスとして定義 -->
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が上書きされてしまうので注意しましょう。

time_formats.rb | 上書きされる例
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メソッドのみで使ったときの結果を変えることができます。

time_formats.rb | 定義の仕方
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を使うとより簡単に変換することが出来る