github.com/qioalice/ekago/v3@v3.3.2-0.20221202205325-5c262d586ee4/ekatime/calendar_private.go (about) 1 // Copyright © 2021. All rights reserved. 2 // Author: Ilya Stroy. 3 // Contacts: iyuryevich@pm.me, https://github.com/qioalice 4 // License: https://opensource.org/licenses/MIT 5 6 package ekatime 7 8 //goland:noinspection GoSnakeCaseUsage 9 const ( 10 _CALENDAR2_DEFAULT_CAPACITY = 366 11 _CALENDAR2_CAUSE_DEFAULT_CAPACITY = 64 12 _CALENDAR2_EVENT_DESCRIPTIONS_DEFAULT_CAPACITY = 16 13 ) 14 15 func (wc *Calendar) dateToIndex(dd Date) uint { 16 17 // WARNING! 18 // Method assumes that wc.year == dd.Year(). 19 20 // Calendar always works as in leap year. 21 // So, we need to increase doy +1 if it's not leap year and march+ month. 22 23 doy := dd.DayOfYear() 24 if dd.Month() >= MONTH_MARCH && !wc.isLeap { 25 doy++ 26 } 27 28 return uint(doy) 29 } 30 31 func (wc *Calendar) rangeOfMonth(m Month) (uint, uint) { 32 33 d := Days(_Table0[m-1]) 34 if m == MONTH_FEBRUARY && wc.isLeap { 35 d++ 36 } 37 38 d1 := _Table2[m-1] 39 d2 := d1 + d - 1 // -1 for d2 be the last day of month 40 41 return uint(d1), uint(d2) 42 } 43 44 func (wc *Calendar) overrideDate(dd Date, eventID EventID, isDayOff, useEventID bool) { 45 46 // 3rd bool argument: 47 // 48 // A: Use provided EventID (`useEventID`), 49 // B: Calendar causing is enabled (`wc.cause != nil`). 50 // 51 // Truth table: 52 // A B Res 53 // 0 0 1 54 // 0 1 1 55 // 1 0 0 56 // 1 1 1 57 // 58 // Thus, it's a material conditional (implication). 59 // Read more: https://en.wikipedia.org/wiki/Material_conditional 60 61 if !(wc.IsValid() && dd.Year() == wc.year && (!useEventID || (wc.cause != nil))) { 62 return 63 } 64 65 idx := wc.dateToIndex(dd) 66 wc.dayOff.Set(idx, isDayOff) 67 68 // SAFETY: 69 // Condition above guarantees if `useEventID` is true, 70 // `wc.cause` is also not nil. 71 if useEventID { 72 wc.cause[idx] = eventID 73 } 74 } 75 76 func (wc *Calendar) nextDay(dd Date, isDayOff bool) Date { 77 78 if !(wc.IsValid() && dd.IsValid() && dd.Year() == wc.year) { 79 return _DATE_INVALID 80 } 81 82 var ( 83 nextDay uint 84 exist bool 85 ) 86 87 if isDayOff { 88 nextDay, exist = wc.dayOff.NextUp(wc.dateToIndex(dd)) 89 } else { 90 nextDay, exist = wc.dayOff.NextDown(wc.dateToIndex(dd)) 91 } 92 93 if !exist { 94 return _DATE_INVALID 95 } 96 97 return NewDateFromDayOfYear(wc.year, Days(nextDay)) 98 } 99 100 func (wc *Calendar) daysIn(m Month, isDayOff bool) []Day { 101 102 if !(wc.IsValid() && m.IsValid()) { 103 return nil 104 } 105 106 // We don't use Month.DaysInForYear() method here, 107 // because it treats years not in range [1900..4095] as invalid years. 108 109 d1, d2 := wc.rangeOfMonth(m) 110 ret := make([]Day, 0, 31) 111 112 if isDayOff { 113 for v, e := wc.dayOff.NextUp(d1 - 1); e && v <= d2; v, e = wc.dayOff.NextUp(v) { 114 ret = append(ret, Day(v-d1)+1) 115 } 116 } else { 117 for v, e := wc.dayOff.NextDown(d1 - 1); e && v <= d2; v, e = wc.dayOff.NextDown(v) { 118 ret = append(ret, Day(v-d1)+1) 119 } 120 } 121 122 return ret 123 } 124 125 func (wc *Calendar) daysInCount(m Month, isDayOff bool) Days { 126 127 if !(wc.IsValid() && m.IsValid()) { 128 return 0 129 } 130 131 // We don't use Month.DaysInForYear() method here, 132 // because it treats years not in range [1900..4095] as invalid years. 133 134 d1, d2 := wc.rangeOfMonth(m) 135 d := Days(d2 - d1 + 1) 136 137 c := Days(wc.dayOff.CountBetween(d1, d2)) 138 if !isDayOff { 139 c = d - c 140 } 141 142 return c 143 } 144 145 func (wc *Calendar) doSaturdayAndSundayDayOff() { 146 147 if !wc.IsValid() { 148 return 149 } 150 151 w := NewDate(wc.year, MONTH_JANUARY, 1).Weekday() 152 var idx uint = 1 153 154 if w == WEEKDAY_SATURDAY { 155 // do nothing, idx already is 1 156 157 } else if w == WEEKDAY_SUNDAY { 158 wc.dayOff.Up(idx) 159 idx += 6 160 161 } else { 162 idx += uint(WEEKDAY_SATURDAY.To06() - w.To06()) 163 } 164 165 for ; idx <= uint(_Table2[MONTH_MARCH-1]); idx += 7 { 166 wc.dayOff.Up(idx) 167 wc.dayOff.Up(idx + 1) 168 } 169 170 if !wc.isLeap { 171 // Calendar's year is always leap (29Feb). 172 // But sometimes the real year might be not leap and weekdays are: 173 // 28 feb sat and 1 mar sun. 174 // 29 feb will be marked as weekday (in loop above). 175 // Index increasing is placed below (after this condition). 176 // And the last thing we need to do is mark 1 mar sun as weekday. 177 // This is exactly what this code do. 178 if idx-6 == uint(_Table2[MONTH_MARCH-1]-1) { 179 wc.dayOff.Up(idx - 5) 180 } 181 idx++ 182 } 183 184 for ; idx <= 366; idx += 7 { 185 wc.dayOff.Up(idx) 186 wc.dayOff.Up(idx + 1) 187 } 188 }