Skip to content

fix(db): decode creationDate/stopDate as Unix epoch, not Core Data - #127

Merged
ryanlewis merged 2 commits into
mainfrom
fix/unix-epoch-dates
Aug 9, 2026
Merged

fix(db): decode creationDate/stopDate as Unix epoch, not Core Data#127
ryanlewis merged 2 commits into
mainfrom
fix/unix-epoch-dates

Conversation

@ryanlewis

Copy link
Copy Markdown
Owner

Problem

things search --json (and every other JSON output path) reported creationDate/stopDate exactly +31 years in the future — a task created 2026-08-09T00:23:25Z emitted creationDate: 2057-08-09T00:23:25Z.

Root cause

Things stores its absolute-timestamp REAL columns (TMTask.creationDate, stopDate, checklist stopDate) as seconds since the Unix epoch (1970), but internal/db decoded them with model.CoreDataToTime, which adds the value to Apple's Core Data reference date (2001-01-01). A 1970-based value fed into a 2001-based decoder lands exactly 31 years late.

Verified against the live DB (read-only):

creationDate = 1786235005.11
datetime(x, 'unixepoch')            → 2026-08-09 00:23:25   ✓ matches actual creation
datetime(x + 978307200, 'unixepoch') → 2057-08-09 00:23:25   ✗ what we emitted

Fix

  • Replace CoreDataToTime/TimeToCoreData with UnixToTime/TimeToUnix. A call-site audit shows no column in the Things schema actually uses the 2001 epoch — startDate/deadline use the separate ThingsDate bit-encoding — so the old codec is deleted outright rather than kept as a second decoder.
  • The logbook stopDate > manualLogDate filter compares column-vs-column in the same epoch, so it was never affected.
  • Regression test pins a real TMTask.creationDate value (1786235005.119778) to its correct 2026 decode; the round-trip and epoch-zero tests now assert against 1970.

Verification

make test, make lint, make build all clean. Rebuilt binary against the live DB: the exact task from the bug report (7vyrVUfNGFgcPq6Q5uv6vb) now emits creationDate: 2026-08-09T00:23:25Z.

Things stores its absolute-timestamp REAL columns (creationDate, stopDate)
as seconds since the Unix epoch, but they were decoded against Apple's
Core Data reference date (2001-01-01), shifting every value exactly +31
years into the future (e.g. a task created 2026-08-09 reported
creationDate 2057-08-09). Anything sorting or filtering on those fields
via JSON output would misbehave.

Replace CoreDataToTime/TimeToCoreData with UnixToTime/TimeToUnix — an
audit of call sites shows no column in the Things schema actually uses
the 2001 epoch (startDate/deadline use the separate ThingsDate
bit-encoding), so the old codec is deleted rather than kept alongside.
The logbook manualLogDate comparison is column-vs-column in the same
epoch and is unaffected.

Adds a regression test pinning a real TMTask creationDate value to its
correct 2026 decode.
Truncation could land one nanosecond short of the stored value due to
float64 representation (0.119778s -> 119777999ns); round instead.
@ryanlewis
ryanlewis merged commit 17a0e9c into main Aug 9, 2026
7 checks passed
@ryanlewis
ryanlewis deleted the fix/unix-epoch-dates branch August 9, 2026 00:37
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant