From 1bc46c9eff4c8d78f5cda741bd8fff2ffee012aa Mon Sep 17 00:00:00 2001 From: DTTerastar Date: Mon, 20 Apr 2026 22:00:10 -0400 Subject: [PATCH] fix: resolve --today against local calendar date --today, --days N, and the default 7-day window previously used time.Now().UTC(), so in timezones west of UTC, "today" flipped to the next day shortly after local evening. At 20:xx ET (~00:xx UTC next day), `crono-export nutrition --today` queried tomorrow's UTC date and returned an empty result even though the user had logged food "today". Resolve the reference day from the user's local zone instead, and construct midnight with time.Date rather than Truncate(24*time.Hour) (which only aligns to midnight in UTC). Explicit --start/--end string parsing is unchanged; the fix only affects the three relative modes. Co-Authored-By: Claude Opus 4.7 (1M context) --- internal/cronoclient/daterange.go | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/internal/cronoclient/daterange.go b/internal/cronoclient/daterange.go index 627b3ff..7e5941d 100644 --- a/internal/cronoclient/daterange.go +++ b/internal/cronoclient/daterange.go @@ -12,7 +12,11 @@ import ( const dateLayout = "2006-01-02" -// DateRange is an inclusive [Start, End] window in UTC. +// DateRange is an inclusive [Start, End] window. Only the calendar date +// (YYYY-MM-DD) of each endpoint is sent to Cronometer's export endpoints, +// so the time-of-day and zone on these values don't round-trip — but the +// calendar date is resolved in the user's local zone so that --today +// matches the day the user sees in the Cronometer UI. type DateRange struct { Start time.Time End time.Time @@ -29,17 +33,18 @@ func AddDateRangeFlags(cmd *cobra.Command) { // ParseDateRangeFromFlags reads the date-range flags off cmd and resolves // them into a concrete DateRange. Default when no flags are passed: the -// last 7 days ending today (UTC). +// last 7 days ending today. "Today" is the user's local calendar day. func ParseDateRangeFromFlags(cmd *cobra.Command) (DateRange, error) { startStr, _ := cmd.Flags().GetString("start") endStr, _ := cmd.Flags().GetString("end") days, _ := cmd.Flags().GetInt("days") today, _ := cmd.Flags().GetBool("today") - return resolveDateRange(startStr, endStr, days, today, time.Now().UTC()) + return resolveDateRange(startStr, endStr, days, today, time.Now()) } func resolveDateRange(startStr, endStr string, days int, today bool, ref time.Time) (DateRange, error) { - now := ref.Truncate(24 * time.Hour) + y, m, d := ref.Date() + now := time.Date(y, m, d, 0, 0, 0, 0, ref.Location()) var start, end time.Time switch {