127 lines
2.8 KiB
Go
127 lines
2.8 KiB
Go
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),
|
|
}
|
|
}
|