Rubyでカレンダー

2012-12-27

Rubyでカレンダーを表示するには、Dateモジュールの機能をいろいろ使って実現する。Dateインスタンスのwdayで曜日(0=日曜、6=土曜)を取得、またDate.new(year, month, -1)でその月の最後の日が取得できることを利用する。

require 'date'

# Returns array of weeks of the year/month.
# wday_start: Start day of week (0=Sun, 1=Mon, ..., 6=Sat)
#
# Example:
# cal(2013, 1)
# => [[nil,nil, 1, 2, 3, 4, 5],
# [ 6, 7, 8, 9, 10, 11, 12],
# [ 13, 14, 15, 16, 17, 18, 19],
# [ 20, 21, 22, 23, 24, 25, 26],
# [ 27, 28, 29, 30, 31]]
def cal(year, month, wday_start = 0)
last_day = Date.new(year, month, -1).day
wday = (Date.new(year, month, 1).wday - wday_start) % 7
weeks = (wday + last_day + 6) / 7

(0 ... weeks).map do |i|
day = i * 7 - wday + 1
if day <= 0 # First week of the month.
[nil] * wday + (1 .. 7 - wday).to_a
elsif day + 7 > last_day # Last week of the month.
(day .. last_day).to_a
else
(day .. day + 6).to_a
end
end
end


if $0 == __FILE__
=begin
2013/1
. . 1 2 3 4 5
6 7 8 9 10 11 12
13 14 15 16 17 18 19
20 21 22 23 24 25 26
27 28 29 30 31
=end
now = Time.now
month = (ARGV.shift || now.month).to_i
year = (ARGV.shift || now.year).to_i

weeks = cal(year, month)

puts "#{year}/#{month}"
weeks.each do |week|
puts week.map {|d| d ? sprintf('%2d', d) : ' .'}.join(' ')
end
end

Codepadで動作を見てみる:http://codepad.org/r7uuRL37

(wday + last_day + 6) / 7でその月に何週あるかを割り出して、初めの週と終わりの週に特殊処理をして、それらを配列として返すので、あとはなんなりと。

月曜始まりにしたい場合とかを考慮して、何曜日を先頭にするかを引数として渡せるようにした。