Open srfoster opened 5 years ago
I have something along these lines in the unreleased sequel to gregor, though it differs from your example in one important respect: "the fourth Thursday of November" is a fine abstract description of Thanksgiving, though to get a date out of it, you'd need to apply it to a year. Whereas the code I have only works with concrete dates. (Your version is similar to the existing concept of a "date period," where you can specify a "period of N years," which has no concrete duration until you add it to an actual date.)
Anyhow, this is what I have right now:
(define (last-day-of-month year month)
(date year month (days-in-month year month)))
(define (nth-wday-in-month year month wday n)
(cond [(>= n 0)
(define first-of-month (date year month))
(define first-of-month-wday (date->wday first-of-month))
(define diff (mod (- wday first-of-month-wday) 7))
(date-add-days first-of-month (+ diff (* 7 (sub1 n))))]
[else
(define last (last-day-of-month year month))
(define last-wday (date->wday last))
(define diff
(let ([d1 (- wday last-wday)])
(cond [(zero? d1) 0]
[(> d1 0) (- d1 7)]
[else d1])))
(date-add-days last (- diff (* 7 (sub1 (- n)))))]))
nth-wday-in-month
has a bit of a strange interface. It's 1-indexed, so (nth-wday-in-month 2018 11 4 4)
would give you the date of the fourth Thursday in November 2018. If you give it a negative value for n
, it counts backwards from the last occurrence of wday
in the month. (The odd case of n=0
gives you the last occurrence of wday
in the month previous. Like I said, strange.)
I'm curious if you have a particular mode of usage in mind for your more abstract interface.
BTW, that definition depends on some other things, like mod
, which is defined in a private math module (it exists in gregor as well as in the newer, unreleased library).
Err... though the negative case for n
appears to be wrong, which is troubling:
> (nth-wday-in-month 2018 11 4 -1)
#<date 2018-12-01>
Update: fixed now:
> (nth-wday-in-month 2018 11 4 -1)
#<date 2018-11-29>
Yeah, that was a silly typo in the cond
. I've updated the source above.
For example, is there some way I could do something analogous to the following?
(define thanksgiving (fourth (thursdays november)))