Groovyで、月曜日から始まる場合や、日曜日から始まる場合などに対応したカレンダー生成スクリプトを作ってみました。
この投稿に触発されたんですが、素のGroovyで書くと結構長くなってしまいました。
もっと良い方法あるんだろうな・・・
real_calendar.groovy
class OneMonthCalendar {
def beginningOfWeek = "Sun"
def year = new Date().year + 1900
def month = new Date().month + 1
def weekSequence = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"]
def List<Date> getCalendar() {
// Javaは日曜日を0として6までの数値を返してくる。
// それに対応する週の項目
def week = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"]
// 表示する週の順番の指定。
weekSequence = week.drop(week.indexOf(beginningOfWeek)) + week.take(week.indexOf(beginningOfWeek))
// 基本となる年月
def baseDate = new Date("$year/$month/1")
// Dateオブジェクトから末日を求める
def getLastDay = {Date date -> date.toCalendar().getActualMaximum(Calendar.DATE)}
def thisMonth= (1..getLastDay(baseDate)).step(1).collect{new Date("$year/$month/$it")}
def daysRequiredLastMonth = weekSequence.indexOf(week[thisMonth.head().day])
def lastMonth = (0 ..< daysRequiredLastMonth).collect{ thisMonth.head() - (it+1) }.reverse()
// 既に一ヶ月のカレンダーとしてフルの場合
if((lastMonth + thisMonth).size() % 7 == 0) {
lastMonth + thisMonth
} else {
def daysRequiredNextMonth = 7 - ((lastMonth + thisMonth).size() % 7)
def nextMonth = (0 ..< daysRequiredNextMonth).collect{ thisMonth.last() + (it+1) }
lastMonth + thisMonth + nextMonth
}
}
}
// インスタンスの生成
def calendar = new OneMonthCalendar(year:2013, month:2, beginningOfWeek:"Sun")
// カレンダーを生成&取得!
def result = calendar.getCalendar()
/**********************************************************
* 以降は表示する際にどうするかなので、ケースバイケースでそれなりに。
*********************************************************/
// Listの中身はDateオブジェクトなので適当にほしい値に変換
perfectOne = result.collect{"${(it.date).toString().padLeft(2,'0')}"}
// とりあえず週の情報を表示してみる
println "${calendar.year}/${calendar.month}".center(35)
calendar.weekSequence.each{print it.center(5, " ")}
println ""
// list(1か月分のDateオブジェクト(カレンダー))を1週間ごとに分けるクロージャ
// 本当は末尾再帰を最適化するようにtrampolineを使って方が良いけど、
// 今回は5回だけの再帰と分かりきっているのでとりあえず無視
// さらに言うとtrampolineの使い方を良く知らないので別途調べる!
def spliter = { List list ->
!list ? [] : [list.take(7)] + call(list.drop(7))
}
// 用意したクロージャで一週間後とに分けられたlistを表示。
spliter(perfectOne).each{ weeks ->
weeks.each{ week ->
print week.center(5, " ")
}
println ""
}
2013年12月で日曜日から始まるカレンダーを出力した結果
new OneMonthCalendar(year:2013, month:12, beginningOfWeek:"Sun")
2013/12
Sun Mon Tue Wed Thu Fri Sat
01 02 03 04 05 06 07
08 09 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30 31 01 02 03 04
2013年12月で月曜日から始まるカレンダーを出力した結果
new OneMonthCalendar(year:2013, month:12, beginningOfWeek:"Mon")
2013/12
Mon Tue Wed Thu Fri Sat Sun
25 26 27 28 29 30 01
02 03 04 05 06 07 08
09 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31 01 02 03 04 05