Koito/internal/db/timeframe.go

118 lines
3 KiB
Go

package db
import (
"time"
)
type Timeframe struct {
Period Period
Year int
Month int
Week int
FromUnix int64
ToUnix int64
From time.Time
To time.Time
}
func TimeframeToTimeRange(tf Timeframe) (t1, t2 time.Time) {
now := time.Now()
loc := now.Location()
// ---------------------------------------------------------------------
// 1. Explicit From / To (time.Time) — highest precedence
// ---------------------------------------------------------------------
if !tf.From.IsZero() {
if tf.To.IsZero() {
return tf.From, now
}
return tf.From, tf.To
}
// ---------------------------------------------------------------------
// 2. Unix timestamps
// ---------------------------------------------------------------------
if tf.FromUnix != 0 {
t1 = time.Unix(tf.FromUnix, 0).In(loc)
if tf.ToUnix == 0 {
return t1, now
}
t2 = time.Unix(tf.ToUnix, 0).In(loc)
return t1, t2
}
// ---------------------------------------------------------------------
// 3. Derived ranges (Year / Month / Week)
// ---------------------------------------------------------------------
// YEAR only
if tf.Year != 0 && tf.Month == 0 && tf.Week == 0 {
start := time.Date(tf.Year, 1, 1, 0, 0, 0, 0, loc)
end := time.Date(tf.Year+1, 1, 1, 0, 0, 0, 0, loc).Add(-time.Second)
return start, end
}
// MONTH (+ optional year)
if tf.Month != 0 {
year := tf.Year
if year == 0 {
year = now.Year()
if int(now.Month()) < tf.Month {
year--
}
}
start := time.Date(year, time.Month(tf.Month), 1, 0, 0, 0, 0, loc)
end := endOfMonth(year, time.Month(tf.Month), loc)
return start, end
}
// WEEK (+ optional year)
if tf.Week != 0 {
year := tf.Year
if year == 0 {
year = now.Year()
_, currentWeek := now.ISOWeek()
if currentWeek < tf.Week {
year--
}
}
// ISO week 1 contains Jan 4
jan4 := time.Date(year, 1, 4, 0, 0, 0, 0, loc)
week1Start := startOfWeek(jan4)
start := week1Start.AddDate(0, 0, (tf.Week-1)*7)
end := endOfWeek(start)
return start, end
}
// ---------------------------------------------------------------------
// 4. Period
// ---------------------------------------------------------------------
if !tf.Period.IsZero() {
return StartTimeFromPeriod(tf.Period), now
}
// ---------------------------------------------------------------------
// 5. Fallback: empty timeframe → zero values
// ---------------------------------------------------------------------
return time.Time{}, time.Time{}
}
func startOfWeek(t time.Time) time.Time {
// ISO week: Monday = 1
weekday := int(t.Weekday())
if weekday == 0 { // Sunday
weekday = 7
}
return time.Date(t.Year(), t.Month(), t.Day()-weekday+1, 0, 0, 0, 0, t.Location())
}
func endOfWeek(t time.Time) time.Time {
return startOfWeek(t).AddDate(0, 0, 7).Add(-time.Second)
}
func endOfMonth(year int, month time.Month, loc *time.Location) time.Time {
startNextMonth := time.Date(year, month+1, 1, 0, 0, 0, 0, loc)
return startNextMonth.Add(-time.Second)
}