hotoolong's blog

プログラムのことやエンジニアリングに関することを記事にしています。

each_sliceを使って簡易カレンダーを作成

仕事が忙しくなってきました。少し大変です。
少しのアイドルがある環境で過ごしたいなと贅沢なことを考えながら、
周りからモチベーションを落とされるというよくわからない状況を奮起しながら程良く頑張っています。

さて本題です。
最近カレンダーを出力したりする場面が多くていい方法がないかと考えてたりします。
配列を7つに区切ってカレンダーのデータを保持できるとちょっと便利だなと思い、
はじめはsliceを使っていたのですが、
each_sliceも結構便利に使えることが分かったので、
簡易カレンダーを実装しました。

t = Date.today.beginning_of_month # 当月の月初
puts t.strftime('%Y年%m月')
(Array.new(t.wday,nil) + (t.day .. t.end_of_month.day).to_a).each_slice(7) do |week|
  puts week.inspect
end
201201月
[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]

このような感じで簡単に出力できます。
putsして出力してますが、配列に格納して入れ子になりますが、後でつかうときに便利です。
上の結果は1月で日曜日始まりですが、2月の場合は以下のとおり、1日以前はnilをいれています。

[nil, 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]

これだと日曜日開始だけの対応になるので、曜日をずらして考えると
月曜日の場合の月初の開始位置が欲しいので、以下のメソッドを作成

#
# start_pos は カレンダー開始曜日 Date#wdayに準じる
#
def week_pos(day, start_pos=1)
  ((7 - start_pos) + day.wday) % 7
end

先ほどの出力部分もメソッドにする

#
# posは曜日を設定 Date#wdayに準じる
#
def cal_data(day, pos=1)
  t = day.beginning_of_month
  cal = []
  (Array.new(week_pos(t, pos),nil) + (t.day .. t.end_of_month.day).to_a).each_slice(7) {|week| cal << week}
  cal
end

あとは呼ぶだけ

t= Date.today
puts cal_data(t).inspect

t.dayしている箇所はそのままDate型で保持してても後で使いやすいです。
もしかすると使う人が意識してeach_slice(7)を読んでくれてもいいかと思いした。

#
# posは曜日を設定 Date#wdayに準じる
# each_slice(7)で区切って使ってくださいませ
#
def cal_data(day, pos=1)
  t = day.beginning_of_month
  Array.new(week_pos(t, pos),nil) + (t.day .. t.end_of_month.day).to_a
end

もっといいやり方があるのかな??