Files
bifrost/framework/configstore/tables/utils.go
Beyhan Oğur 880f412e2c first commit
2026-04-26 21:52:23 +03:00

92 lines
3.0 KiB
Go

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)
}
}