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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
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
}
|