github.com/keysonzzz/kmg@v0.0.0-20151121023212-05317bfd7d39/kmgTime/Period.go (about) 1 package kmgTime 2 3 import ( 4 "errors" 5 "fmt" 6 "reflect" 7 "sort" 8 "time" 9 ) 10 11 //小时区间,取值范围[0,24] 12 type PeriodHour struct { 13 Start int 14 End int 15 } 16 17 // a period time start from Start,end to End, 18 // start must before or equal end 19 type Period struct { 20 Start time.Time 21 End time.Time 22 } 23 24 type PeriodGetter interface { 25 GetPeriod() Period 26 } 27 28 var ReflectTypePeriodGetter = reflect.TypeOf((*PeriodGetter)(nil)).Elem() 29 var NotFoundError = errors.New("not found") 30 31 func (p Period) IsIn(t time.Time) bool { 32 if t.After(p.End) { 33 return false 34 } 35 if t.Before(p.Start) { 36 return false 37 } 38 return true 39 } 40 41 func (p Period) IsValid() bool { 42 if p.End.Before(p.Start) { 43 return false 44 } else { 45 return true 46 } 47 } 48 49 func leq(a, b time.Time) bool { 50 return a.Before(b) || a.Equal(b) 51 } 52 53 func (p Period) Overlaps(b Period) bool { 54 return (leq(b.Start, p.Start) && leq(p.Start, b.End)) || 55 (leq(p.Start, b.Start) && leq(b.Start, p.End)) 56 } 57 58 // start must before or equal end 59 func NewPeriod(Start time.Time, End time.Time) (period Period, err error) { 60 if Start.After(End) { 61 err = fmt.Errorf("[kmgTime.NewPeriod] Start.After(End) Start:%s End:%s", Start, End) 62 return 63 } 64 return Period{Start: Start, End: End}, nil 65 } 66 67 func MustNewPeriod(Start time.Time, End time.Time) (period Period) { 68 period, err := NewPeriod(Start, End) 69 if err != nil { 70 panic(err) 71 } 72 return period 73 } 74 75 //SortedList should sort by start time and should not overlap each other 76 func GetPeriodFromSortedList(t time.Time, SortedList []Period) (index int, ok bool) { 77 n := len(SortedList) 78 i := sort.Search(n, func(i int) bool { 79 return SortedList[i].End.After(t) 80 }) 81 if i == n { 82 return 0, false 83 } 84 if !(SortedList[i].Start.Before(t) || SortedList[i].Start.Equal(t)) { 85 return 0, false 86 } 87 return i, true 88 } 89 90 //实现1,反射 91 func GetPeriodFromGenericSortedList(t time.Time, SortedList interface{}) (index int, err error) { 92 reflectList := reflect.Indirect(reflect.ValueOf(SortedList)) 93 if reflectList.Kind() != reflect.Slice && reflectList.Kind() != reflect.Array { 94 panic(fmt.Errorf("[GetPeriodFromGenericSortedList] need array or slice get %s", reflectList.Kind().String())) 95 } 96 if !reflectList.Type().Elem().Implements(ReflectTypePeriodGetter) { 97 panic(fmt.Errorf("[GetPeriodFromGenericSortedList] need elem implement 'PeriodGetter' get %s", 98 reflectList.Elem().Type().Name())) 99 } 100 n := reflectList.Len() 101 i := sort.Search(n, func(i int) bool { 102 return reflectList.Index(i).Interface().(PeriodGetter).GetPeriod().End.After(t) 103 }) 104 if i == n { 105 return 0, NotFoundError 106 } 107 if !reflectList.Index(i).Interface().(PeriodGetter).GetPeriod().Start.Before(t) { 108 return 0, NotFoundError 109 } 110 return i, nil 111 } 112 113 type PeriodSlice []Period 114 115 func (p PeriodSlice) Len() int { 116 return len(p) 117 } 118 119 func (p PeriodSlice) Less(i, j int) bool { 120 return p[i].Start.Before(p[j].Start) 121 } 122 func (p PeriodSlice) Swap(i, j int) { 123 p[i], p[j] = p[j], p[i] 124 } 125 126 func PeriodSort(p []Period) { 127 sort.Sort(PeriodSlice(p)) 128 } 129 130 //实现2,interface 131 type PeriodListInterface interface { 132 Len() int 133 GetPeriodAtIndex(i int) Period 134 Swap(i, j int) 135 } 136 137 func SelectPeriodFromSortedPeriodList(t time.Time, PeriodList PeriodListInterface) (index int, ok bool) { 138 n := PeriodList.Len() 139 i := sort.Search(n, func(i int) bool { 140 return PeriodList.GetPeriodAtIndex(i).End.After(t) 141 }) 142 if i == n { 143 return 0, false 144 } 145 currentPeriod := PeriodList.GetPeriodAtIndex(i) 146 if !(currentPeriod.Start.Before(t) || currentPeriod.Start.Equal(t)) { 147 return 0, false 148 } 149 return i, true 150 } 151 152 type periodListSorter struct { 153 PeriodListInterface 154 } 155 156 func (p periodListSorter) Less(i, j int) bool { 157 return p.GetPeriodAtIndex(i).Start.Before(p.GetPeriodAtIndex(j).Start) 158 } 159 func PeriodListSort(PeriodList PeriodListInterface) { 160 sort.Sort(periodListSorter{PeriodList}) 161 } 162 163 //实现3,数据结构分离 164 type PeriodList []PeriodListElement 165 166 type PeriodListElement struct { 167 Period 168 OriginIndex int 169 } 170 171 func (p PeriodList) Len() int { 172 return len(p) 173 } 174 func (p PeriodList) Less(i, j int) bool { 175 return p[i].Period.Start.Before(p[j].Period.Start) 176 } 177 func (p PeriodList) Swap(i, j int) { 178 p[i], p[j] = p[j], p[i] 179 } 180 181 func (p PeriodList) Sort() { 182 sort.Sort(p) 183 } 184 185 //sort it first 186 func (p PeriodList) SelectFromTime(t time.Time) (OriginIndex int, ok bool) { 187 n := p.Len() 188 i := sort.Search(n, func(i int) bool { 189 return p[i].End.After(t) 190 }) 191 if i == n { 192 return 0, false 193 } 194 currentPeriod := p[i] 195 if !(currentPeriod.Start.Before(t) || currentPeriod.Start.Equal(t)) { 196 return 0, false 197 } 198 return p[i].OriginIndex, true 199 } 200 201 //sort it first 202 func (p PeriodList) IsIncludeOverlap() bool { 203 for i := 0; i < len(p)-1; i++ { 204 if p[i].Overlaps(p[i+1].Period) { 205 return true 206 } 207 } 208 return false 209 } 210 func (p PeriodList) SetAtIndex(period Period, i int) { 211 p[i] = PeriodListElement{Period: period, OriginIndex: i} 212 } 213 214 //向后追加一个时间段,index为追加前的长度 215 func (p PeriodList) Append(period Period) PeriodList { 216 return append(p, PeriodListElement{Period: period, OriginIndex: len(p)}) 217 }