first commit
This commit is contained in:
91
framework/configstore/tables/utils.go
Normal file
91
framework/configstore/tables/utils.go
Normal file
@@ -0,0 +1,91 @@
|
||||
package tables
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
)
|
||||
|
||||
// IsCalendarAlignableDuration reports whether the given duration string supports calendar-aligned resets.
|
||||
// Only day ("d"), week ("w"), month ("M"), and year ("Y") suffixes have natural calendar boundaries.
|
||||
// Sub-day durations like "1h", "30m" are not alignable.
|
||||
func IsCalendarAlignableDuration(duration string) bool {
|
||||
if duration == "" {
|
||||
return false
|
||||
}
|
||||
switch duration[len(duration)-1] {
|
||||
case 'd', 'w', 'M', 'Y':
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
// GetCalendarPeriodStart returns the start of the current calendar period for the given duration and time.
|
||||
// For calendar-scale durations (daily, weekly, monthly, yearly) it snaps to clean boundaries in UTC:
|
||||
// - "Nd" → midnight UTC on the current day
|
||||
// - "Nw" → midnight UTC on the most recent Monday
|
||||
// - "NM" → midnight UTC on the 1st of the current month
|
||||
// - "NY" → midnight UTC on Jan 1 of the current year
|
||||
//
|
||||
// For all other durations (e.g. "1h", "30m") the original time t is returned unchanged,
|
||||
// since sub-day periods don't have a natural calendar boundary.
|
||||
func GetCalendarPeriodStart(duration string, t time.Time) time.Time {
|
||||
if duration == "" {
|
||||
return t
|
||||
}
|
||||
t = t.UTC()
|
||||
suffix := duration[len(duration)-1:]
|
||||
switch suffix {
|
||||
case "d":
|
||||
return time.Date(t.Year(), t.Month(), t.Day(), 0, 0, 0, 0, time.UTC)
|
||||
case "w":
|
||||
weekday := int(t.Weekday())
|
||||
// Sunday = 0, so shift to Monday = 0
|
||||
daysFromMonday := (weekday + 6) % 7
|
||||
monday := t.AddDate(0, 0, -daysFromMonday)
|
||||
return time.Date(monday.Year(), monday.Month(), monday.Day(), 0, 0, 0, 0, time.UTC)
|
||||
case "M":
|
||||
return time.Date(t.Year(), t.Month(), 1, 0, 0, 0, 0, time.UTC)
|
||||
case "Y":
|
||||
return time.Date(t.Year(), time.January, 1, 0, 0, 0, 0, time.UTC)
|
||||
default:
|
||||
return t
|
||||
}
|
||||
}
|
||||
|
||||
// ParseDuration function to parse duration strings
|
||||
func ParseDuration(duration string) (time.Duration, error) {
|
||||
if duration == "" {
|
||||
return 0, fmt.Errorf("duration is empty")
|
||||
}
|
||||
|
||||
// Handle special cases for days, weeks, months, years
|
||||
switch {
|
||||
case duration[len(duration)-1:] == "d":
|
||||
days := duration[:len(duration)-1]
|
||||
if d, err := time.ParseDuration(days + "h"); err == nil {
|
||||
return d * 24, nil
|
||||
}
|
||||
return 0, fmt.Errorf("invalid day duration: %s", duration)
|
||||
case duration[len(duration)-1:] == "w":
|
||||
weeks := duration[:len(duration)-1]
|
||||
if w, err := time.ParseDuration(weeks + "h"); err == nil {
|
||||
return w * 24 * 7, nil
|
||||
}
|
||||
return 0, fmt.Errorf("invalid week duration: %s", duration)
|
||||
case duration[len(duration)-1:] == "M":
|
||||
months := duration[:len(duration)-1]
|
||||
if m, err := time.ParseDuration(months + "h"); err == nil {
|
||||
return m * 24 * 30, nil // Approximate month as 30 days
|
||||
}
|
||||
return 0, fmt.Errorf("invalid month duration: %s", duration)
|
||||
case duration[len(duration)-1:] == "Y":
|
||||
years := duration[:len(duration)-1]
|
||||
if y, err := time.ParseDuration(years + "h"); err == nil {
|
||||
return y * 24 * 365, nil // Approximate year as 365 days
|
||||
}
|
||||
return 0, fmt.Errorf("invalid year duration: %s", duration)
|
||||
default:
|
||||
return time.ParseDuration(duration)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user