package main import ( "time" ) func _daysIn(t time.Time) int { y, m, _ := t.Date() t2 := time.Date(y, m+1, 1, 0, 0, 0, 0, time.UTC) return t2.AddDate(0, 0, -1).Day() } type SelectableMonth struct { Ws [7]bool S [32]bool Year, Pad, DaysIn int Month time.Month Weekday time.Weekday } func NewMonth(t time.Time) *SelectableMonth { t = time.Date(t.Year(), t.Month(), 1, 0, 0, 0, 0, time.Local) ret := &SelectableMonth{} ret.Year, ret.Month, ret.Weekday = t.Year(), t.Month(), t.Weekday() ret.DaysIn = _daysIn(t) ret.Pad = int(ret.Weekday) return ret } func _newMonth(y int, m time.Month) SelectableMonth { return *NewMonth(time.Date(y, m, 1, 0, 0, 0, 0, time.Local)) } func (sm *SelectableMonth) Refresh() { *sm = _newMonth(sm.Year, sm.Month) } func (sm *SelectableMonth) Previous() { m, y := sm.Month-1, sm.Year if m > 11 { m = 0 y += 1 } *sm = _newMonth(y, m) } func (sm *SelectableMonth) Next() { m, y := sm.Month+1, sm.Year if m < 0 { m = 11 y -= 1 } *sm = _newMonth(y, m) } func (sm *SelectableMonth) SelectWeekday(d time.Weekday) *SelectableMonth { for i := int(d) + 1 - sm.Pad; i <= 31; i += 7 { if i < 0 { continue } sm.S[i] = true } sm.Ws[d] = true return sm } func (sm *SelectableMonth) DeselectWeekday(d time.Weekday) *SelectableMonth { for i := int(d) + 1 - sm.Pad; i <= 31; i += 7 { if i < 0 { continue } sm.S[i] = false } sm.Ws[d] = false return sm } func (sm *SelectableMonth) CheckSel() *SelectableMonth { alldays := func(d time.Weekday) bool { for i := int(d) + 1 - sm.Pad; i <= 31; i += 7 { if i < 1 { continue } if !sm.S[i] { return false } } return true } for d := time.Sunday; d < 7; d++ { if alldays(d) { sm.Ws[d] = true } else { sm.Ws[d] = false } } return sm } func (sm *SelectableMonth) Weekdays() int { var i int for w := 0; w <= 6; w++ { for d := 1; d < 6; d++ { x := w*7 + d + 1 - sm.Pad if x < 0 || x >= sm.DaysIn { break } if sm.S[x] { i++ } } } return i } func (sm *SelectableMonth) Weekends() int { var i int for w := 0; w <= 6; w++ { x := w*7 + 1 - sm.Pad if x < 0 { continue } if x >= sm.DaysIn { break } if sm.S[x] { i++ } x = w*7 + 6 + 1 - sm.Pad if x < 0 || x >= sm.DaysIn { break } if sm.S[x] { i++ } } return i } // a day within a SelectableMonth type Day struct { Num int sm *SelectableMonth } func (sm *SelectableMonth) Day(i int) *Day { ret := &Day{Num: i, sm: sm} return ret.ifexists() } func (d *Day) exists() bool { if d == nil { return false } if d.Num > d.sm.DaysIn || d.Num <= 0 { return false } else { return true } } func (d *Day) ifexists() *Day { if d.exists() { return d } else { return nil } } func (d *Day) Next() *Day { ret := &Day{d.Num + 1, d.sm} return ret.ifexists() } func (d *Day) Prev() *Day { ret := &Day{d.Num - 1, d.sm} return ret.ifexists() } func (sm *SelectableMonth) Days() []*Day { ret := make([]*Day, 0) for d := sm.Day(1); d.exists(); d = d.Next() { ret = append(ret, d) } return ret } func (d *Day) Weekday() time.Weekday { return time.Weekday((d.Num + d.sm.Pad - 1) % 7) } func (d *Day) Selected() bool { return d.sm.S[d.Num] } // a week within a SelectableMonth type Week struct { Num int sm *SelectableMonth } func (w *Week) exists() bool { if w == nil { return false } return w.Day(1).exists() // first day of this week exists } func (w *Week) ifexists() *Week { if w.exists() { return w } else { return nil } } // week of a month, starting with Sundays except for the first week func (sm *SelectableMonth) Week(i int) *Week { ret := &Week{i, sm} return ret.ifexists() } func (sm *SelectableMonth) Weeks() []*Week { ret := make([]*Week, 0) for w := sm.Week(1); w.exists(); w = w.Next() { ret = append(ret, w) } return ret } func (w *Week) Day(i int) *Day { if i < 1 || i > 7 { return nil } wday := (w.Num-1)*7 + i if w.Num != 1 { wday -= w.sm.Pad } ret := &Day{wday, w.sm} return ret.ifexists() } func (w *Week) Next() *Week { ret := &Week{w.Num + 1, w.sm} return ret.ifexists() } func (w *Week) Prev() *Week { ret := &Week{w.Num - 1, w.sm} return ret.ifexists() } func (w *Week) Days() []*Day { ret := make([]*Day, 0) for d := w.Day(1); d.In(w); d = d.Next() { ret = append(ret, d) } return ret } func (d *Day) In(w *Week) bool { if d == nil { return false } fd := w.Day(1) if d.Num < fd.Num { return false } if d.Num > fd.Num && d.Weekday() == time.Sunday { return false } return true }