Fix dashboard date bucketing

This commit is contained in:
zhx 2026-05-26 15:53:42 +08:00
parent d7f507916f
commit 4877da1d74
2 changed files with 66 additions and 4 deletions

View File

@ -6,7 +6,7 @@ import (
)
func PeriodWindows(eventTime time.Time, statZone *time.Location) []PeriodWindow {
localDate := startOfDay(eventTime.In(statZone))
localDate := startOfDay(wallClockInLocation(eventTime, statZone))
dayEnd := localDate.AddDate(0, 0, 1)
weekday := int(localDate.Weekday())
@ -59,8 +59,8 @@ func SamePeriod(left time.Time, right time.Time, window PeriodWindow, statZone *
if window.Type == PeriodAll {
return true
}
leftLocal := left.In(statZone)
rightLocal := right.In(statZone)
leftLocal := wallClockInLocation(left, statZone)
rightLocal := wallClockInLocation(right, statZone)
switch window.Type {
case PeriodDay:
return startOfDay(leftLocal).Equal(startOfDay(rightLocal))
@ -76,7 +76,7 @@ func SamePeriod(left time.Time, right time.Time, window PeriodWindow, statZone *
}
func DailyDate(eventTime time.Time, storageZone *time.Location) time.Time {
return startOfDay(eventTime.In(storageZone))
return startOfDay(wallClockInLocation(eventTime, storageZone))
}
func DateNumber(day time.Time) int {
@ -93,3 +93,15 @@ func startOfDay(value time.Time) time.Time {
year, month, date := value.Date()
return time.Date(year, month, date, 0, 0, 0, 0, value.Location())
}
func wallClockInLocation(value time.Time, location *time.Location) time.Time {
if value.IsZero() {
return value
}
if location == nil {
location = time.UTC
}
year, month, day := value.Date()
hour, minute, second := value.Clock()
return time.Date(year, month, day, hour, minute, second, value.Nanosecond(), location)
}

View File

@ -0,0 +1,50 @@
package dashboard
import (
"testing"
"time"
)
func TestDailyDateKeepsDatabaseDatetimeCalendarDay(t *testing.T) {
riyadh := mustLoadLocation(t, "Asia/Riyadh")
eventTime := time.Date(2026, 5, 26, 1, 30, 0, 0, time.UTC)
got := DailyDate(eventTime, riyadh)
if got.Format("2006-01-02") != "2026-05-26" {
t.Fatalf("DailyDate shifted database DATETIME calendar day: got %s", got.Format("2006-01-02"))
}
if got.Location() != riyadh {
t.Fatalf("DailyDate location = %s, want %s", got.Location(), riyadh)
}
}
func TestPeriodWindowsKeepsDatabaseDatetimeCalendarDay(t *testing.T) {
riyadh := mustLoadLocation(t, "Asia/Riyadh")
eventTime := time.Date(2026, 5, 26, 1, 30, 0, 0, time.UTC)
windows := PeriodWindows(eventTime, riyadh)
if windows[0].Type != PeriodDay || windows[0].Key != "2026-05-26" {
t.Fatalf("day window = %+v, want key 2026-05-26", windows[0])
}
}
func TestSamePeriodKeepsDatabaseDatetimeCalendarDay(t *testing.T) {
riyadh := mustLoadLocation(t, "Asia/Riyadh")
left := time.Date(2026, 5, 26, 0, 10, 0, 0, time.UTC)
right := time.Date(2026, 5, 26, 23, 50, 0, 0, time.UTC)
if !SamePeriod(left, right, PeriodWindow{Type: PeriodDay}, riyadh) {
t.Fatal("SamePeriod shifted database DATETIME values out of the same calendar day")
}
}
func mustLoadLocation(t *testing.T, name string) *time.Location {
t.Helper()
location, err := time.LoadLocation(name)
if err != nil {
t.Fatalf("load location %s: %v", name, err)
}
return location
}