Groovyで決まった月のカレンダーを任意の曜日はじまりの形で生成する方法


[この投稿](http://qiita.com/saba1024/items/d1a12314829116b6d2ab)のコードがあまりにも長かったので自分なりに作ってみました。

実装ルール(要件)はこんな感じ。

* 任意の年月を指定して1ヶ月分のカレンダーを出力する
* 週のはじまりの曜日を指定できる(日曜・月曜以外でも指定可能…用途があるかは置いといて)
* 週単位で、前月・次月の日付も表示する

Groovy の処理系は [java.util.Calendar](http://docs.oracle.com/javase/7/docs/api/java/util/Calendar.html) を[拡張している](http://groovy.codehaus.org/groovy-jdk/java/util/Calendar.html)のでこれを使わない手はありません。Java の資産を活用してこその Groovy です。

```groovy:MyCalendar.groovy

def DAY_OF_WEEKS = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"]

def getMonth = { year, month, firstDay=Calendar.SUNDAY ->
    def cal = Calendar.instance     // Java の Calendar.getInstance() 相当
    cal.set(year, month-1, 1)       // month-1 は Calendar クラスの仕様による
    cal.setFirstDayOfWeek(firstDay) // 週のはじまる曜日をセット
    
    // その月に何週あるかを取得
    def weeks = cal.getActualMaximum( Calendar.WEEK_OF_MONTH )
    
    // カレンダーのヘッダ部分(不要なら def result = [] とかしておく)
    def result = [["","$year/$month","(starts","with",DAY_OF_WEEKS[firstDay-1]+")"]]
    result.add( (0..6).collect{ DAY_OF_WEEKS[(firstDay-1+it)%7] } )
    
    // 週のはじまる曜日まで日付をさかのぼる
    while( cal.get(Calendar.DAY_OF_WEEK) != firstDay ){ cal = cal.previous() }
    
    // 各週の日付を出力
    weeks.times { result.add( (0..6).collect{ (cal++).get( Calendar.DAY_OF_MONTH ) as String } ) }
    return result
}

// こっちは表示用なので適当に
def printMonth = { month ->
    month.each{ week ->
        week.each{ print it.padLeft(3) + " " }
        println ""
    }
    println ""
}

def one = getMonth(2013,11,Calendar.MONDAY)
printMonth(one)

one = getMonth(2013,9,Calendar.MONDAY)
printMonth(one)

one = getMonth(2013,6,Calendar.MONDAY)
printMonth(one)

one = getMonth(2013,11)
printMonth(one)

one = getMonth(2013,9)
printMonth(one)

one = getMonth(2013,6)
printMonth(one)

one = getMonth(2013,6,Calendar.SATURDAY)
printMonth(one)

one = getMonth(2013,6,Calendar.TUESDAY)
printMonth(one)

```

出力はこんな感じになります。

```
    2013/11 (starts with Mon) 
Mon Tue Wed Thu Fri Sat Sun 
 28  29  30  31   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 

    2013/9 (starts with Mon) 
Mon Tue Wed Thu Fri Sat Sun 
 26  27  28  29  30  31   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 

    2013/6 (starts with Mon) 
Mon Tue Wed Thu Fri Sat Sun 
 27  28  29  30  31   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 

    2013/11 (starts with Sun) 
Sun Mon Tue Wed Thu Fri Sat 
 27  28  29  30  31   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 

    2013/9 (starts with Sun) 
Sun Mon Tue Wed Thu Fri Sat 
  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 

    2013/6 (starts with Sun) 
Sun Mon Tue Wed Thu Fri Sat 
 26  27  28  29  30  31   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 

    2013/6 (starts with Sat) 
Sat Sun Mon Tue Wed Thu Fri 
  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 

    2013/6 (starts with Tue) 
Tue Wed Thu Fri Sat Sun Mon 
 28  29  30  31   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 

```

[format()](http://groovy.codehaus.org/groovy-jdk/java/util/Calendar.html#format%28java.lang.String%29)を使えば曜日の表記を自前で持つ必要すら無いんですが、個々の日付に曜日を出すわけではないのでそこはなんとなくサボりました。

WebアプリケーションではDatePicker系のJavascriptライブラリが充実しているので、あまり使い道はないかもしれませんね。