summaryrefslogtreecommitdiff
path: root/cmd/gen-imworkingon/calendar.go
diff options
context:
space:
mode:
Diffstat (limited to 'cmd/gen-imworkingon/calendar.go')
-rw-r--r--cmd/gen-imworkingon/calendar.go122
1 files changed, 122 insertions, 0 deletions
diff --git a/cmd/gen-imworkingon/calendar.go b/cmd/gen-imworkingon/calendar.go
new file mode 100644
index 0000000..29c3318
--- /dev/null
+++ b/cmd/gen-imworkingon/calendar.go
@@ -0,0 +1,122 @@
+package main
+
+import (
+ "time"
+)
+
+//////////////////////////////////////////////////////////////////////
+
+type Date struct {
+ Year int
+ Month time.Month
+ Day int
+}
+
+func DateOf(t time.Time) Date {
+ y, m, d := t.Date()
+ return Date{Year: y, Month: m, Day: d}
+}
+
+func (d Date) Time() time.Time {
+ return time.Date(d.Year, d.Month, d.Day, 0, 0, 0, 0, time.Local)
+}
+
+func (d Date) AddDays(delta int) Date {
+ return DateOf(d.Time().AddDate(0, 0, delta))
+}
+
+func (d Date) Weekday() time.Weekday {
+ return d.Time().Weekday()
+}
+
+func (a Date) Cmp(b Date) int {
+ switch {
+ case a.Year < b.Year:
+ return -1
+ case a.Year > b.Year:
+ return 1
+ }
+ switch {
+ case a.Month < b.Month:
+ return -1
+ case a.Month > b.Month:
+ return 1
+ }
+ switch {
+ case a.Day < b.Day:
+ return -1
+ case a.Day > b.Day:
+ return 1
+ }
+ return 0
+}
+
+//////////////////////////////////////////////////////////////////////
+
+type CalendarDay[T any] struct {
+ Date
+ Data T
+}
+
+//////////////////////////////////////////////////////////////////////
+
+// keyed by time.Weekday
+type CalendarWeek[T any] [7]CalendarDay[T]
+
+//////////////////////////////////////////////////////////////////////
+
+// must be sorted, must be non-sparse
+type Calendar[T any] []CalendarWeek[T]
+
+func (c Calendar[T]) NumWeekdaysInMonth(weekday time.Weekday, target Date) int {
+ num := 0
+ for _, w := range c {
+ if w[weekday].Date == (Date{}) {
+ continue
+ }
+ switch {
+ case w[weekday].Year == target.Year:
+ switch {
+ case w[weekday].Month == target.Month:
+ num++
+ case w[weekday].Month > target.Month:
+ return num
+ }
+ case w[weekday].Year > target.Year:
+ return num
+ }
+ }
+ return num
+}
+
+//////////////////////////////////////////////////////////////////////
+
+func BuildCalendar[T any](things []T, dateOfThing func(T) Date) Calendar[T] {
+ if len(things) == 0 {
+ return nil
+ }
+
+ newestDate := DateOf(time.Now().Local())
+
+ oldestDate := dateOfThing(things[0])
+ byDate := make(map[Date]T, len(things))
+ for _, thing := range things {
+ date := dateOfThing(thing)
+ if oldestDate.Cmp(date) > 0 {
+ oldestDate = date
+ }
+ byDate[date] = thing
+ }
+
+ var ret Calendar[T]
+ for date := oldestDate; date.Cmp(newestDate) <= 0; date = date.AddDays(1) {
+ if len(ret) == 0 || date.Weekday() == 0 {
+ ret = append(ret, CalendarWeek[T]{})
+ }
+ ret[len(ret)-1][date.Weekday()] = CalendarDay[T]{
+ Date: date,
+ Data: byDate[date],
+ }
+ }
+ return ret
+}