VictoriaMetrics/app/vmctl/stepper/split.go

83 lines
2.3 KiB
Go
Raw Normal View History

package stepper
import (
"fmt"
"sort"
"time"
)
const (
// StepMonth represents a one month interval
StepMonth string = "month"
// StepWeek represents a one week interval
StepWeek string = "week"
// StepDay represents a one day interval
StepDay string = "day"
// StepHour represents a one hour interval
StepHour string = "hour"
// StepMinute represents a one minute interval
StepMinute string = "minute"
)
// SplitDateRange splits start-end range in a subset of ranges respecting the given step
// Ranges with granularity of StepMonth are aligned to 1st of each month in order to improve export efficiency at block transfer level
func SplitDateRange(start, end time.Time, step string, timeReverse bool) ([][]time.Time, error) {
if start.After(end) {
return nil, fmt.Errorf("start time %q should come before end time %q", start.Format(time.RFC3339), end.Format(time.RFC3339))
}
var nextStep func(time.Time) (time.Time, time.Time)
switch step {
case StepMonth:
nextStep = func(t time.Time) (time.Time, time.Time) {
endOfMonth := time.Date(t.Year(), t.Month()+1, 1, 0, 0, 0, 0, t.Location()).Add(-1 * time.Nanosecond)
if t == endOfMonth {
endOfMonth = time.Date(t.Year(), t.Month()+2, 1, 0, 0, 0, 0, t.Location()).Add(-1 * time.Nanosecond)
t = time.Date(t.Year(), t.Month()+1, 1, 0, 0, 0, 0, t.Location())
}
return t, endOfMonth
}
case StepDay:
nextStep = func(t time.Time) (time.Time, time.Time) {
return t, t.AddDate(0, 0, 1)
}
case StepWeek:
nextStep = func(t time.Time) (time.Time, time.Time) {
return t, t.Add(7 * 24 * time.Hour)
}
case StepHour:
nextStep = func(t time.Time) (time.Time, time.Time) {
return t, t.Add(time.Hour * 1)
}
case StepMinute:
nextStep = func(t time.Time) (time.Time, time.Time) {
return t, t.Add(time.Minute * 1)
}
default:
return nil, fmt.Errorf("failed to parse step value, valid values are: '%s', '%s', '%s', '%s'. provided: '%s'",
StepMonth, StepDay, StepHour, StepMinute, step)
}
currentStep := start
ranges := make([][]time.Time, 0)
for end.After(currentStep) {
s, e := nextStep(currentStep)
if e.After(end) {
e = end
}
ranges = append(ranges, []time.Time{s, e})
currentStep = e
}
if timeReverse {
sort.SliceStable(ranges, func(i, j int) bool {
return ranges[i][0].After(ranges[j][0])
})
}
return ranges, nil
}