LoginSignup
1
1

More than 5 years have passed since last update.

Groovyでカレンダーを生成する方法

Posted at

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 
1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1