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  }