19
8

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【Ruby】日付・時刻操作まとめ:require "date"とrequire "time"の使い分けと使い方

Posted at

はじめに

Rubyで日付や時刻を扱うには、標準ライブラリの Date、DateTime、Time クラスを活用します。これらは require "date" や require "time" で使えるようになります。本記事では、それぞれのクラスが何を扱うか、どのようなメソッドで操作できるかを網羅的に解説します。

1. Time クラス(組み込み + require 'time')

1. 何を扱う?

  • 日付 + 時刻 + タイムゾーン情報
  • 秒・分・時間まで含む「現在時刻」や「特定の時刻」を表す

2. 主な使い方

p t = Time.now # 現在の時刻  例: 2025-04-06 21:46:31.430407 +0900
p t - 3600     # 1時間前    例: 2025-04-06 20:46:31.430407 +0900
p t + 60       # 60秒後     例: 2025-04-06 21:47:31.430407 +0900

p t.year # 2025
p t.month # 4
p t.day # 6
p t.strftime("%Y-%m-%d") # "2025-04-06"

3. require 'time' で拡張される機能

  • Time.parse(string) で文字列をパースできるようになる。「文字列をパースする」とは、文字列(String)を意味のあるデータ構造に変換することを指します。
  • Time.parse は人間がよく使う形式のいろんな書き方に対応しています:
require "time"
p Time.parse("2025-04-06 10:00:00")  # => Time オブジェクト 例: 2025-04-06 10:00:00 +0900
p Time.parse("06 Apr 2025 10:00:00") # => Time オブジェクト 例: 2025-04-06 10:00:00 +0900
p Time.parse("2025/04/06 10:00")     # => Time オブジェクト 例: 2025-04-06 10:00:00 +0900

# 特定フォーマットの文字列を Time に変換
p Time.iso8601("2025-04-06T10:00:00+09:00")      # => ISO 8601 形式  2025-04-06 10:00:00 +0900
p Time.rfc2822("Sun, 6 Apr 2025 10:00:00 +0900") # => RFC 2822 形式  2025-04-06 10:00:00 +0900
p Time.httpdate("Sun, 06 Apr 2025 01:00:00 GMT") # => HTTP 日付形式  2025-04-06 01:00:00 UTC

# Time オブジェクトをフォーマットに合わせた文字列に変換
p now = Time.now # => 2025-04-06 21:58:52.383212 +0900
p now.iso8601    # => "2025-04-06T21:58:52+09:00"
p now.rfc2822    # => "Sun, 06 Apr 2025 21:58:52 +0900"
p now.httpdate   # => "Sun, 06 Apr 2025 12:58:52 GMT"

補足1: ISO形式(ISO 8601形式)とは?

  • API通信(JSONの日付フィールド)や DBとのデータやり取りなどでよく使う。
  • 国際標準の「日付と時刻の書き方」
  • 基本の形(日時)YYYY-MM-DDThh:mm:ss±hh:mm 2025-04-06T10:00:00+09:00
  • 2025-04-06 → 日付(年-月-日)
  • T → 時間の区切り文字(Timeの「T」)
  • 10:00:00 → 時刻(時:分:秒)
  • +09:00 → タイムゾーン(日本時間はUTC+9)
    image.png

補足2: UTCとは?

  • 協定世界時(Coordinated Universal Time)のこと。
  • 地球上での「基準となる時間」で、全世界共通の“ゼロ基準の時間”です。
  • 地球基準の時計=UTC。時間のズレをなくすための世界共通の時間。経度0度(イギリス・グリニッジ)を基準。「GMT(グリニッジ標準時)」に近い(ほぼ同じと考えてOK)
  • 日本時間(JST)は UTCより9時間進んでいる ので:
    UTC:  2025-04-06T01:00:00Z
    JST:  2025-04-06T10:00:00+09:00
    
    • Z は「Zuluタイム」の略(=UTCのこと)
    • +09:00 は UTC からの時差を表してる

2. Date クラス(require 'date')

1. 何を扱う?

  • 日付のみ(時刻なし)
  • 年・月・日を操作するのに向いている

2. 主な使い方

require "date"

# 基本的な生成と取得
p Date.today                 # => 今日の日付 #<Date: 2025-04-06 ((2460772j,0s,0n),+0s,2299161j)>
p Date.new(2025, 4, 1)       # => 2025-04-01 #<Date: 2025-04-01 ((2460767j,0s,0n),+0s,2299161j)>
p Date.parse("2025-04-06")   # => 文字列から変換 #<Date: 2025-04-06 ((2460772j,0s,0n),+0s,2299161j)>

puts "----------------------------"

# 日付の演算
d = Date.new(2025, 4, 6)

p d + 1            # => 翌日(2025-04-07) #<Date: 2025-04-07 ((2460773j,0s,0n),+0s,2299161j)>
p d - 7            # => 1週間前(2025-03-30) #<Date: 2025-03-30 ((2460765j,0s,0n),+0s,2299161j)>
p d.next_day(3)    # => 3日後(2025-04-09) #<Date: 2025-04-09 ((2460775j,0s,0n),+0s,2299161j)>
p d.prev_month     # => 前の月(2025-03-06) #<Date: 2025-03-06 ((2460741j,0s,0n),+0s,2299161j)>
p d.next_month(2)  # => 2ヶ月後(2025-06-06) #<Date: 2025-06-06 ((2460833j,0s,0n),+0s,2299161j)>

puts "----------------------------"

# 曜日チェック
p d.wday        # => 0(日曜日)※0〜6(Sun〜Sat)
p d.sunday?     # => true
p d.monday?     # => false

puts "----------------------------"

# フォーマット変換(文字列
p d.strftime("%Y-%m-%d")      # => "2025-04-06"
p d.strftime("%B %d, %Y")     # => "April 06, 2025"
p d.strftime("%Y年%m月%d日")  # => "2025年04月06日"

puts "----------------------------"

# 文字列からの変換(フォーマット指定あり)
puts Date.strptime("06/04/2025", "%d/%m/%Y") # => 2025-04-06
puts Date.strptime("20250406", "%Y%m%d")     # => 2025-04-06

puts "----------------------------"

# 日付の比較
puts a = Date.new(2025, 4, 6) # 2025-04-06
puts b = Date.new(2025, 4, 1) # 2025-04-01

p a > b   # true
p a == b  # false

puts "----------------------------"

# 範囲を使ったループ
from_date = Date.new(2025, 4, 1)
to_date = Date.new(2025, 4, 5)

(from_date..to_date).each do |date|
  puts date.strftime("%Y-%m-%d")
end

# 出力:
# 2025-04-01
# 2025-04-02
# 2025-04-03
# 2025-04-04
# 2025-04-05

puts "----------------------------"

# 月末・月初

d = Date.new(2025, 4, 6)

puts Date.new(d.year, d.month, 1)    # => 2025-04-01
puts Date.new(d.year, d.month, -1)   # => 2025-04-30

3. DateTime クラス(require 'date')

1. 何を扱う?

  • 日付 + 時刻(でも Time より機能が少ない)
  • タイムゾーン操作など一部の場面では Time より使いやすいことも

2. 主な使い方

require "date"

p dt = DateTime.now # 現在の時刻 #<DateTime: 2025-04-06T22:28:32+09:00 ((2460772j,48512s,198739000n),+32400s,2299161j)>

puts "----------------------------"

# 時刻の各要素を取得
puts dt = DateTime.new(2025, 4, 6, 15, 30, 45) # => 2025-04-06T15:30:45+00:00

puts dt.year    # => 2025
puts dt.month   # => 4
puts dt.day     # => 6
puts dt.hour    # => 15
puts dt.minute  # => 30
puts dt.second  # => 45

puts "----------------------------"

# 日付や時刻の加減算(演算)
puts dt + 1  # 翌日 => 2025-04-07T15:30:45+00:00
puts dt - 1  # 前日 => 2025-04-05T15:30:45+00:00

puts "----------------------------"

# フォーマット文字列の活用
puts dt.strftime("%Y/%m/%d %H:%M:%S")  # => "2025/04/06 15:30:00"
puts dt.strftime("%A, %d %B %Y")       # => "Sunday, 06 April 2025"
puts dt.strftime("%Y年%-m月%-d日 %H時%M分") # => "2025年4月6日 15時30分"

puts "----------------------------"

# 文字列からの変換
puts DateTime.parse("2025-04-06T15:30:00+09:00")  # 2025-04-06T15:30:00+09:00
puts DateTime.strptime("06/04/2025 15:30", "%d/%m/%Y %H:%M")  # 2025-04-06T15:30:00+00:00

puts "----------------------------"

# タイムゾーンの扱い(オフセット指定)
puts dt = DateTime.new(2025, 4, 6, 15, 30, 0, "+09:00")
puts dt.zone      # => "+09:00"
puts dt.offset    # => 3/8 (9/24)

# UTC変換
puts dt.new_offset(0)  # => UTC時刻(+00:00)に変換 2025-04-06T06:30:00+00:00

puts "----------------------------"

dt1 = DateTime.parse("2025-04-06T10:00:00")
dt2 = DateTime.parse("2025-04-07T10:00:00")

p dt1 < dt2  # => true
p (dt1..dt2).cover?(DateTime.parse("2025-04-06T12:00:00"))  # => true

puts "----------------------------"

# 日付・時刻だけ取り出したいとき

puts dt = DateTime.now # => 2025-04-06T22:37:28+09:00

puts dt.to_date    # => 2025-04-06
puts dt.to_time    # => 2025-04-06 22:37:28 +0900

4. クラスの使い分けまとめ

image.png

5. 実践問題

Q1. 今日が週の何日目かを数値と文字列で出力せよ

# 出力例: 0 (Sunday)
# 出力例: Sunday

回答

require "date"

today = Date.today
puts today.wday         # => 0〜6(0は日曜)
puts today.strftime("%A") # => "Sunday"など英語の曜日

Q2. 指定された年月に含まれる土日の日数を求めよ

# 入力: 2025年4月
# 出力: 土日が何日あるか

回答

require "date"

def weekend_count(year, month)
  first_day = Date.new(year, month, 1)
  last_day = Date.new(year, month, -1)

  (first_day..last_day).count { |d| d.saturday? || d.sunday? }
end

puts weekend_count(2025, 4)  # => 8

Q3. 2つの日付の間にある平日・休日の数を数えよ

# 入力: Date型2つ
# 出力: 平日と休日の数(祝日は無視)

回答

require "date"

def count_weekdays_and_weekends(from, to)
  weekdays = 0
  weekends = 0

  (from..to).each do |date|
    if date.saturday? || date.sunday?
      weekends += 1
    else
      weekdays += 1
    end
  end

  { weekdays: weekdays, weekends: weekends }
end

start_date = Date.parse("2025-04-01")
end_date = Date.parse("2025-04-10")

result = count_weekdays_and_weekends(start_date, end_date)
puts result
# => {:weekdays=>8, :weekends=>2}

Q4. 日付の配列から、最も未来に近い日を求めよ

# 入力: Date配列
# 出力: 今日より未来のうち、最も近い日付

回答

require "date"

def nearest_future_date(dates)
  today = Date.today
  future_dates = dates.select { |d| d > today }
  future_dates.min
end

dates = [
  Date.new(2025, 4, 10),
  Date.new(2025, 4, 5),
  Date.new(2025, 4, 8)
]

puts nearest_future_date(dates)
# 今日が2025-04-06 なら => 2025-04-08

Q5. 「yyyy-mm-dd」形式の文字列配列から、昇順でソートせよ

# 入力: ["2025-04-10", "2023-01-01", "2024-12-31"]
# 出力: ["2023-01-01", "2024-12-31", "2025-04-10"]

回答

require "date"

def sort_date_strings(array)
  array.map { |s| Date.parse(s) }
      .sort
      .map(&:to_s)
end

dates = ["2025-04-10", "2023-01-01", "2024-12-31"]
puts sort_date_strings(dates)
# => ["2023-01-01", "2024-12-31", "2025-04-10"]

おわりに

Rubyは Time と Date をしっかり使い分けることで、複雑な日付処理も簡潔に書くことができます。標準ライブラリながら強力な機能を活かして、実務でも使えるコードをどんどん書いていきましょう!

また、株式会社シンシアでは、実務未経験のエンジニアの方や学生エンジニアインターンを採用し一緒に働いています。
※ シンシアにおける働き方の様子はこちら

弊社には年間100人程度の実務未経験の方に応募いただき、技術面接を実施しております。
この記事が少しでも学びになったという方は、ぜひ wantedly のストーリーもご覧いただけるととても嬉しいです!

19
8
0

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
19
8

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?