mirror of
https://github.com/VictoriaMetrics/VictoriaMetrics.git
synced 2024-12-26 20:30:10 +01:00
63fc200f16
See https://github.com/VictoriaMetrics/VictoriaMetrics/issues/5376
(cherry picked from commit 6af732b6f7
)
83 lines
2.3 KiB
Go
83 lines
2.3 KiB
Go
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
|
|
}
|