47 lines
1.4 KiB
Go
47 lines
1.4 KiB
Go
// Package daterange resolves recurring calendar windows and normalized dates.
|
|
package daterange
|
|
|
|
import "time"
|
|
|
|
// CalendarWindow resolves a recurring month/day range around now. A range whose
|
|
// start month is after its end month crosses the year boundary.
|
|
func CalendarWindow(now time.Time, monthFrom int, dayFrom *int, monthTo int, dayTo *int) (time.Time, time.Time) {
|
|
location := now.Location()
|
|
startYear := now.Year()
|
|
if monthFrom > monthTo && int(now.Month()) <= monthTo {
|
|
startYear--
|
|
}
|
|
endYear := startYear
|
|
if monthFrom > monthTo {
|
|
endYear++
|
|
}
|
|
startDay := 1
|
|
if dayFrom != nil {
|
|
startDay = clampDay(startYear, time.Month(monthFrom), *dayFrom)
|
|
}
|
|
endDay := daysInMonth(endYear, time.Month(monthTo))
|
|
if dayTo != nil {
|
|
endDay = clampDay(endYear, time.Month(monthTo), *dayTo)
|
|
}
|
|
return time.Date(startYear, time.Month(monthFrom), startDay, 0, 0, 0, 0, location), time.Date(endYear, time.Month(monthTo), endDay, 23, 59, 59, 0, location)
|
|
}
|
|
|
|
// Date returns value at midnight in its original location.
|
|
func Date(value time.Time) time.Time {
|
|
return time.Date(value.Year(), value.Month(), value.Day(), 0, 0, 0, 0, value.Location())
|
|
}
|
|
|
|
func daysInMonth(year int, month time.Month) int {
|
|
return time.Date(year, month+1, 0, 0, 0, 0, 0, time.UTC).Day()
|
|
}
|
|
|
|
func clampDay(year int, month time.Month, day int) int {
|
|
if maximum := daysInMonth(year, month); day > maximum {
|
|
return maximum
|
|
}
|
|
if day < 1 {
|
|
return 1
|
|
}
|
|
return day
|
|
}
|