LoginSignup
1
1

More than 5 years have passed since last update.

[Groovy]本物のカレンダーのように1ヶ月35日分のカレンダーを生成する。

Posted at

こんなのとか

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

実際のソースは以下。

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回だけの再帰と分かりきっているのでとりあえず無視
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 ""
}
1
1
2

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