読者です 読者をやめる 読者になる 読者になる

日付のRangeを週に切り出すスクリプト

バイトの月報を作るのにあたって,日付のRangeを渡すと週ごとに分割するコードを書いています.つまり,

     April 2008
Su Mo Tu We Th Fr Sa
       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

これを,

       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

こうしたい.

勉強中のRubyでコードをかいてみました.まず,テストケースのtest_gen_weeks.rb

require 'gen_weeks'
require 'test/unit'
require 'date'

class GenWeeksTest < Test::Unit::TestCase
  def test_gen_week
    weeks = gen_week(Date.new(2008, 4, 1) .. Date.new(2008, 4, 21))
    assert_equal(
      [ 
        (  Date.new(2008, 4,  1) .. Date.new(2008, 4,  6)  ),
        (  Date.new(2008, 4,  7) .. Date.new(2008, 4, 13)  ),
        (  Date.new(2008, 4, 14) .. Date.new(2008, 4, 20)  ),
        (  Date.new(2008, 4, 21) .. Date.new(2008, 4, 21)  )
      ],
      weeks
    )
  end
end

4月21日ような付きの途中で止まっても動くようにします.

この中で使っているgen_week関数を実装したのが,以下のコードのgen_week.rbです.

require 'date'

def gen_week(range)
  weeks = []
  
  week_start = week_end = range.begin
  loop {
    # 日曜日までインクリメント
    loop {
      break if week_end.wday == 0
      week_end = week_end.next
    }   
        
    # 終端に達していたら脱出
    if week_end >= range.end
      week_end = range.end
      weeks.push(week_start .. week_end)
      break
    end

    # 一週間を登録
    weeks.push(week_start .. week_end)
    week_start = week_end = week_end.next
  }

  return weeks
end

なんかぜんぜんRubyっぽくない!きっと一発できれいに各方法があるはず.ちょっとRangeやDateのメソッドを見てきます.