Skip to content

Commit f0b52ff

Browse files
DTTerastarclaude
andauthored
fix: resolve dates and bucket timestamps in local time (#14)
Two bug classes were mixing UTC and local time across the CLI: 1. Absolute date flags (--since 2025-01-01, show 2025-03-08) used time.Parse which defaults to UTC. In EDT that's Jan 1 midnight UTC = Dec 31 8pm local, so --since silently included yesterday evening's data and show <date> returned workouts from the wrong calendar day. Relative flags (--since 7d, today, yesterday) already anchored to local time, so the two forms of the same flag had different semantics. 2. API timestamps (StartedAt, RFC3339 with the server's zone) were formatted to YYYY-MM-DD without converting to local first. A 11pm local workout (4am UTC next day) bucketed under the wrong date in stats and monthly bodyweight averages, and failed to match in 'workouts show <date>'. Fix is mechanical: ParseInLocation(..., time.Local) for user date parsing, and .Local() before every Format("2006-01-02") used as a bucket key or display string. Co-authored-by: Claude Opus 4.7 (1M context) <[email protected]>
1 parent 2acd482 commit f0b52ff

3 files changed

Lines changed: 6 additions & 5 deletions

File tree

cmd/bodyweights.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,7 @@ func loadBodyweightEntries(sinceFlag string) ([]bodyweightEntry, error) {
105105
if err != nil {
106106
continue
107107
}
108+
date = date.Local()
108109
if !since.IsZero() && date.Before(since) {
109110
continue
110111
}

cmd/stats.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,7 @@ func buildSummaries(posts []Post) []ExerciseSummary {
103103
for _, p := range posts {
104104
bw, _ := strconv.ParseFloat(strings.TrimSpace(p.Bodyweight), 64)
105105
t, _ := time.Parse(time.RFC3339Nano, p.StartedAt)
106-
date := t.Format("2006-01-02")
106+
date := t.Local().Format("2006-01-02")
107107

108108
for _, e := range p.ExerciseData {
109109
ss := sessionStats(e, bw)

cmd/workouts.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ var listCmd = &cobra.Command{
8787

8888
func parseSince(s string) (time.Time, error) {
8989
// Try absolute date first
90-
if t, err := time.Parse("2006-01-02", s); err == nil {
90+
if t, err := time.ParseInLocation("2006-01-02", s, time.Local); err == nil {
9191
return t, nil
9292
}
9393
// Try relative: e.g. 30d, 4w, 6m, 1y
@@ -137,7 +137,7 @@ var showCmd = &cobra.Command{
137137
if err != nil {
138138
continue
139139
}
140-
if t.Format("2006-01-02") == target.Format("2006-01-02") {
140+
if t.Local().Format("2006-01-02") == target.Format("2006-01-02") {
141141
matched = append(matched, p)
142142
}
143143
}
@@ -162,7 +162,7 @@ func parseDate(s string) (time.Time, error) {
162162
case "yesterday":
163163
return now.AddDate(0, 0, -1), nil
164164
}
165-
if t, err := time.Parse("2006-01-02", s); err == nil {
165+
if t, err := time.ParseInLocation("2006-01-02", s, time.Local); err == nil {
166166
return t, nil
167167
}
168168
return time.Time{}, fmt.Errorf("invalid date: %q (use YYYY-MM-DD, today, or yesterday)", s)
@@ -223,7 +223,7 @@ func printFitdown(posts []Post) error {
223223
if err != nil {
224224
fmt.Printf("Workout %s\n", post.StartedAt)
225225
} else {
226-
fmt.Printf("Workout %s\n", t.Format("January 2, 2006"))
226+
fmt.Printf("Workout %s\n", t.Local().Format("January 2, 2006"))
227227
}
228228

229229
if post.SessionNotes != "" {

0 commit comments

Comments
 (0)