package chartjs import ( "sync" "time" ) const ( Minute = "minute" Hour = "hour" Day = "day" Method = "method" ) // 时间序列值, 实现了按时间进行分组的值计算 type TimeSeries struct { mutex sync.Mutex step string values []*TimeseriesValue } func (s *TimeSeries) cutTimeSeries(tm time.Time) int64 { switch s.step { case Method: return time.Date(tm.Year(), tm.Month(), 0, 0, 0, 0, 0, time.Local).Unix() case Day: return time.Date(tm.Year(), tm.Month(), tm.Day(), 0, 0, 0, 0, time.Local).Unix() case Hour: return time.Date(tm.Year(), tm.Month(), tm.Day(), tm.Hour(), 0, 0, 0, time.Local).Unix() default: return time.Date(tm.Year(), tm.Month(), tm.Day(), tm.Hour(), tm.Minute(), 0, 0, time.Local).Unix() } } func (s *TimeSeries) truncateTime(ts int64) int64 { tm := time.Unix(ts, 0) switch s.step { case Method: return time.Date(tm.Year(), tm.Month(), 0, 0, 0, 0, 0, time.Local).Unix() case Day: return time.Date(tm.Year(), tm.Month(), tm.Day(), 0, 0, 0, 0, time.Local).Unix() case Hour: return time.Date(tm.Year(), tm.Month(), tm.Day(), tm.Hour(), 0, 0, 0, time.Local).Unix() default: return time.Date(tm.Year(), tm.Month(), tm.Day(), tm.Hour(), tm.Minute(), 0, 0, time.Local).Unix() } return tm.Unix() } func (s *TimeSeries) nextTimestamp(ts int64) int64 { tm := time.Unix(ts, 0) switch s.step { case Method: return tm.AddDate(0, 1, 0).Unix() case Day: return tm.AddDate(0, 0, 1).Unix() case Hour: return ts + 3600 default: return ts + 60 } } func (s *TimeSeries) Inc(tm time.Time, value float64) { s.mutex.Lock() defer s.mutex.Unlock() ts := s.cutTimeSeries(tm) for _, v := range s.values { if v.Timestamp == ts { v.Value += value return } } s.values = append(s.values, &TimeseriesValue{ Timestamp: ts, Value: value, }) } func (s *TimeSeries) Dec(tm time.Time, value float64) { s.mutex.Lock() defer s.mutex.Unlock() ts := s.cutTimeSeries(tm) for _, v := range s.values { if v.Timestamp == ts { v.Value -= value return } } } func (s *TimeSeries) Values(sts, ets int64) []*TimeseriesValue { var ( nextStamp int64 ) sts = s.truncateTime(sts) ets = s.truncateTime(ets) series := make([]*TimeseriesValue, 0, len(s.values)) nextStamp = sts for _, row := range s.values { for row.Timestamp > nextStamp { series = append(series, &TimeseriesValue{ Timestamp: nextStamp, Value: 0, }) nextStamp = s.nextTimestamp(nextStamp) } series = append(series, row) nextStamp = s.nextTimestamp(nextStamp) } for ets > nextStamp { series = append(series, &TimeseriesValue{ Timestamp: nextStamp, Value: 0, }) nextStamp = s.nextTimestamp(nextStamp) } return series } func NewTimeSeries(step string) *TimeSeries { return &TimeSeries{ step: step, values: make([]*TimeseriesValue, 0, 64), } }