srfi-19ライブラリの<date>型の値を与えて、「“要素数7のリスト”のリスト」でその月のカレンダーを表現するにはどうしたら良いでしょうか?
例:
((#f 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 31 #f #f #f))
この例ではこの月の最初の日は月曜日なので、最初の週を表現するリストの先頭要素、つまり日曜日の位置に#fを置いてカレンダーを表現しています。
月の最初の日までの曜日を埋める
月の最初の日までの曜日を#fで埋めるにはどうしたらよいでしょうか?
「ある日付を与えてその日の曜日を曜日を得る」で見たように、ある日付の曜日の値を得るにはsrfi-19ライブラリのdate-week-day手続きが使えます。
例:
gosh> (use srfi-19)
gosh> (date-week-day
(make-date 0 0 0 0 1 1 2007 (date-zone-offset (current-date))))
1 ;; 月曜日
曜日の値は日曜日なら0、月曜日なら1、...土曜日なら6なのですから、曜日の値の数ぶんの要素数を持つリストをmake-list手続きで生成してやれば良いのです。
例:
gosh> (make-list
(date-week-day
(make-date 0 0 0 0 1 1 2007 (date-zone-offset (current-date))))
#f)
(#f)
先頭を埋めた日付のリストを作る
「ある日付を与えてその月の最初の日を求める」で見たように、その月の最初の日を求めるfirst-day-of-month手続きは次の通りに書けました。
(use srfi-19)
(define (make-month m y)
(make-date 0 0 0 0 1 m y (date-zone-offset (current-date))))
(define (first-day-of-month date)
(make-month (date-month date) (date-year date)))
また、「その月の日数を求める」で見たように、月の日数を求めるdays-of-month手続きは次の通りに書けました。
(define (next-month date)
(if (= (date-month date) 12)
(make-month 1 (+ (date-year date) 1))
(make-month (+ (date-month date) 1) (date-year date))))
(define (days-of-month date)
(inexact->exact
(round
(- (date->modified-julian-day (next-month date))
(date->modified-julian-day (first-day-of-month date))))))
「連続した数を要素とするリストを生成する」で見たように、その月の日付からなるリストを生成するにはsrfi-1のiota手続きが使えました。その月の日数分の連続した数からなるリストを得るには、days-of-month手続きで得た日数ぶんのリストをiota手続きで生成してやれば良いことになります。
例:
gosh> (iota (days-of-month (current-date)) 1)
(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 31)
月の最初の日までの曜日を#fで埋めたリストと日数分のリストを連結してやれば、その月のカレンダーの元になるリストが得られそうです。
例:
gosh> (append
(make-list
(date-week-day
(first-day-of-month (current-date))))
(iota (days-of-month (current-date)) 1))
(#f 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 31)
util.listライブラリのslices手続きを使って、このリストを要素7のリストに分割すればリストのリストでカレンダーを表現することができます。
例:
gosh> (slices
(append
(make-list
(date-week-day
(first-day-of-month (current-date))))
(iota (days-of-month (current-date))))
7 #t #f)
((#f 0 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 #f #f #f))
カレンダーを生成するdate-slices-of-month手続きを書く
上記から、任意の日付dateを与えて「“要素数7のリスト”のリスト」でカレンダーを生成するdate-slices-of-month手続きは次の通りに書けます。
(define (date-slices-of-month date)
(slices (append (make-list (date-week-day (first-day-of-month date)) #f)
(iota (days-of-month date) 1))
7 #t #f))