| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182 |
- package util
- import (
- "fmt"
- "regexp"
- "strconv"
- "time"
- "github.com/opencost/opencost/core/pkg/util/timeutil"
- )
- var intervalRegex = regexp.MustCompile(`^(\d+)(s|m|h|d|w)$`)
- // Interval is a time period defined by a string with a integer followed by a letter (ex: 5d = 5 days)
- type Interval interface {
- // Add adds the interval multiplied by the given int to the given time. (A 10m interval called with 3 would add 30
- // minutes to the given time)
- Add(time.Time, int) time.Time
- // Truncate returns the start of the interval that the given time is a part off
- Truncate(time time.Time) time.Time
- }
- func NewInterval(def string) (Interval, error) {
- match := intervalRegex.FindStringSubmatch(def)
- if match == nil {
- return nil, fmt.Errorf("failed to parse interval '%s'", def)
- }
- num, err := strconv.ParseInt(match[1], 10, 64)
- // This should not happen
- if err != nil {
- panic(fmt.Sprintf("NewInterval: regex failure on int '%s'", def))
- }
- switch match[2] {
- case "s":
- return &durationInterval{time.Duration(num) * time.Second}, nil
- case "m":
- return &durationInterval{time.Duration(num) * time.Minute}, nil
- case "h":
- return &durationInterval{time.Duration(num) * time.Hour}, nil
- case "d":
- return &durationInterval{time.Duration(num) * timeutil.Day}, nil
- case "w":
- return &weekInterval{int(num)}, nil
- default:
- panic(fmt.Sprintf("NewInterval: regex failure on unit '%s'", def))
- }
- }
- type durationInterval struct {
- duration time.Duration
- }
- func (d *durationInterval) Add(t time.Time, i int) time.Time {
- return t.Add(d.duration * time.Duration(i))
- }
- func (d *durationInterval) Truncate(time time.Time) time.Time {
- return time.UTC().Truncate(d.duration)
- }
- // weekInterval is an interval that tracks multiples of weeks with the week starting on Sunday
- type weekInterval struct {
- count int
- }
- func (w *weekInterval) Add(t time.Time, num int) time.Time {
- return t.Add(timeutil.Week * time.Duration(num*w.count))
- }
- // Truncate to the nearest Sunday that is a multiple of the count starting from 0000-31-12
- func (w *weekInterval) Truncate(t time.Time) time.Time {
- // add a day to Sundays to prevent times that would truncate to themselves from going to the previous step
- if t.UTC().Weekday() == time.Sunday {
- t = t.UTC().AddDate(0, 0, 1)
- }
- // truncate to monday using a weekly duration multiple (0001-01-01 was a monday) then subtract a day
- return t.UTC().Truncate(timeutil.Week * time.Duration(w.count)).Add(-timeutil.Day)
- }
|