Rubyの日付操作【プログラミング初心者向け教材】

プログラミング

日付の生成、加算・減算、比較、フォーマットなどの操作は、プログラミングでよくある操作の1つです。

データベースやAPIなどで外部と日付データを送受信する際には、決まったフォーマットにする必要があります。

そのため、プログラミング初心者にとって、日付操作は学習すべき事項の1つとなります。

本記事では、Rubyでよく使われる日付操作について解説します。

プログラミング初心者の方の学習や、忘れてしまった方の復習として、参考にしていただければ幸いです。

記載しているプログラムは、Ruby2.7.1を使って動作確認をしています。

Rubyの日付操作

よくある日付操作として、以下の内容を採り上げます。

  • 日付を扱うクラス
  • 日時の生成
  • 日時・曜日の取得
  • 日時の加算・減算
  • 日時の差分
  • 日時の比較
  • 日時から文字列へのフォーマット
  • 文字列から日時への変換
  • ライブラリの利用

日付を扱うクラス

Rubyで日付を扱う主なクラスには以下があります。

  • Dateクラス:日付のみを扱うクラスです。タイムゾーンを保持しません。使用する場合は require ‘date’ が必要です。
  • DateTimeクラス:日時を扱うクラスです。タイムゾーンも扱えます。使用する場合は require ‘date’ が必要です。
  • Timeクラス:日時を扱うクラスです。DateTimeに追加で、サマータイム、うるう秒を扱うことができます。基本的に require なしで使用できますが、parseのような一部メソッドの使用には require ‘time’ が必要となります。

上記の3クラスはいずれもRubyの標準で提供されるクラスです。
特別な理由がない限り、DateTimeクラスよりもTimeクラスを利用することをおすすめします。
今回はTimeクラスを中心に解説していきます。

日時の生成

Timeクラスを生成するには、大きく2つの方法があります。

現在時刻で生成する方法

t = Time.new
puts t # -> 2020-10-22 09:23:32 +0900

任意の日時を指定して生成する方法

t = Time.local(2020, 10, 22)
puts t # -> 2020-10-22 00:00:00 +0900
t = Time.local(2020, 10, 22, 9, 1, 2, 3)
puts t.iso8601(6) # -> 2020-10-22T09:01:02.000003+09:00

日時・曜日の取得

日時の各属性値を取得する方法

日時の各メソッドを呼出すことで取得することができます。

t = Time.local(2020, 10, 22, 9, 1, 2, 3)
puts t.year # -> 2020
puts t.month # -> 10
puts t.day # -> 22
puts t.hour # -> 9
puts t.min # -> 1
puts t.sec # -> 2
puts t.usec # -> 3
puts t.nsec # -> 3000
puts t.yday # -> 296
puts t.tv_sec # -> 1603324862

ydayは、1月1日を1とした通算日を取得します。
tv_secは、起算時(1970年1月1日午前0時)からの経過秒数を取得します。

曜日を取得する方法

曜日の取得は、wdayメソッドを使います。結果は以下の意味を持つ数値で取得します。

0:日曜日、1:月曜日、2:火曜日、3:水曜日、4:木曜日、5:金曜日、6:土曜日
t = Time.local(2020, 10, 22, 9, 1, 2, 3) # 2020/10/22は木曜日
puts t.wday # -> 4

日時が該当する曜日かどうかをBooleanで取得するメソッドも提供されています。

t = Time.local(2020, 10, 22, 9, 1, 2, 3) # 2020/10/22は木曜日
puts t.sunday? # -> false
puts t.monday? # -> false
puts t.tuesday? # -> false
puts t.wednesday? # -> false
puts t.thursday? # -> true
puts t.friday? # -> false
puts t.saturday? # -> false

日時の加算・減算

日時の加算や減算を行うには、Timeオブジェクトに対して、+演算子または-演算子で、加算・減算したい値を秒で指定します。

日時の加算

t = Time.local(2020, 1, 1)
puts t + 1 # -> 2020-01-01 00:00:01 +0900
puts t + (60 * 60 * 24) # -> 2020-01-02 00:00:00 +0900

日時の減算

t = Time.local(2020, 1, 1)
puts t - 1 # -> 2019-12-31 23:59:59 +0900
puts t - (60 * 60 * 24) # -> 2019-12-31 00:00:00 +0900

日時の差分

日時の差分を取得するには、Timeオブジェクト同士を減算します。差分は秒(Float)で取得されます。

t1 = Time.local(2020, 1, 1)
t2 = Time.local(2020, 10, 22, 9, 1, 2, 3)
puts t2 - t1 # -> 25520462.000003

日時の比較

日時の前後を比較にするには、比較演算子を使う方法と、<=>メソッドを使う方法があります。

比較演算子を使う方法

t1 = Time.local(2020, 1, 1)
t2 = Time.local(2020, 10, 22, 9, 1, 2, 3)
puts t1 < t2 # -> true
puts t1 <= t2 # -> true
puts t1 == t2 # -> false
puts t1 >= t2 # -> false
puts t1 > t2 # -> false

<=>メソッドを使う方法

左辺が大きい場合は1、等しい場合は0、小さい場合は-1を返します。

t1 = Time.local(2020, 1, 1)
t2 = Time.local(2020, 10, 22, 9, 1, 2, 3)
puts t1 <=> t2 # -> -1

日時から文字列へのフォーマット

日時から文字列へ変換してフォーマットするには、strftimeメソッドを使います。

t = Time.local(2020, 10, 22, 9, 1, 2, 3)
puts t.strftime("日時は %Y/%m/%d %T です") # -> 日時は 2020/10/22 09:01:02 です

strftimeメソッドに指定できる書式の詳細はリファレンスマニュアルをご覧ください。

文字列から日時への変換

文字列からTimeオブジェクトへ変換するには、parseメソッドを使う方法とstrptimeメソッドを使う方法があります。
どちらも require ‘time’ が必要となります。

parseメソッドを使う方法

様々なフォーマットに対応しています。

t = Time.parse("2020/10/22 09:01:02")
puts t # -> 2020-10-22 09:01:02 +0900
t = Time.parse("2020-10-22 9:1:2")
puts t # -> 2020-10-22 09:01:02 +0900
t = Time.parse("20201022 090102")
puts t # -> 2020-10-22 09:01:02 +0900

strptimeメソッドを使う方法

第2引数に書式を指定することで、日本語を含むような日時でも変換することが可能です。

t = Time.strptime("2020/10/22 09:01:02", "%Y/%m/%d %T")
puts t # -> 2020-10-22 09:01:02 +0900
t = Time.strptime("2020年10月22日 9時1分2秒", "%Y年%m月%d日 %H時%M分%S秒")
puts t # -> 2020-10-22 09:01:02 +0900

ライブラリの利用

Rubyで日付操作をするための外部ライブラリを1つ紹介します。
Ruby on Railsとともによく使われるライブラリがActive Supportです。

Active Support

Timeオブジェクトでは簡単に出来なかった日付操作を行うことができます。

t = Time.local(2020, 10, 22, 9, 1, 2, 3)
# 昨日
puts t.yesterday # -> 2020-10-21 09:01:02 +0900
# 明日
puts t.tomorrow # -> 2020-10-23 09:01:02 +0900
# 先週の始め(月曜日)
puts t.prev_week # -> 2020-10-12 00:00:00 +0900
# 来週の土曜日
puts t.next_week(:saturday) # -> 2020-10-31 00:00:00 +0900
# 月初
puts t.beginning_of_month # -> 2020-10-01 00:00:00 +0900
# 月末
puts t.end_of_month # -> 2020-10-31 23:59:59 +0900
# 1日後
puts t + 1.days # -> 2020-10-23 09:01:02 +0900
# 2週間後
puts t + 2.week # -> 2020-11-05 09:01:02 +0900
# 3年前
puts t - 3.years # -> 2017-10-22 09:01:02 +0900

日付操作には十分なテストが必要

日付と文字列を変換していると、環境によって時間が変わってしまうことがあります。

また、クライアントとサーバで日時をやり取りすると時間がが変わってしまうなどもあります。

こうした環境による時間の変化は、タイムゾーンが原因であることが考えられます。

実際のプロジェクトでは、データベースはどのタイムゾーンなのか、サーバはどのタイムゾーンで設定するのか、クライアントはどのタイムゾーンで表示するのかといったことを最初に決めておく必要があります。

これらを統一しておかないと、意図せず異なった日時で保存されてしまったり、間違った時間を元に処理が動いてしまったりといったことが発生します。

また、うるう年やうるう秒など、特定の時にだけ発生する時間差などもあります。

過去にもこうした対策がきちんと行われていないことが原因で、大きなトラブルになった事例もあります。

日付を扱う際には、実装時にも注意し、テストを十分に行うことをおすすめします。

今回はRubyの日付操作について紹介しました。

参考になれば幸いです。

コメント

タイトルとURLをコピーしました