Skip to content

fix: prevent negative task durations and day end times - #277

Merged
AdamJ merged 2 commits into
mainfrom
fix/negative-durations
Oct 19, 2026
Merged

AdamJ merged 2 commits into
mainfrom
fix/negative-durations

Conversation

@AdamJ

@AdamJ AdamJ commented Oct 19, 2026

Copy link
Copy Markdown
Owner

Summary

Task durations and a day's end time could go negative. endDay rounds the end time to the nearest 15 minutes while a running task's start is unrounded, so ending a day shortly after starting a task (task started 9:20, day ended 9:21, end rounded to 9:15) produced a negative duration and an end time before the task began. This PR removes that path and the other places that subtract timestamps without a floor, and rejects end-before-start entries in the archive editors.

Type of Change

  • New feature
  • Update to existing feature
  • Bug fix
  • Documentation update
  • Other (describe below)

Related Issue

No linked issue.

Changes Made

  • src/utils/timeUtil.ts: new zero-floored elapsedMs, plus isEndBeforeStart and END_BEFORE_START_MESSAGE. formatDuration and formatDurationLong show negatives as zero.
  • src/contexts/TimeTrackingContext.tsx: endDay never ends earlier than the day start, the running task's start, or the latest recorded task end. beginTask, adjustTaskTime, and the planned-task completion path use elapsedMs. adjustTaskTime collapses an end-before-start edit to a zero-length task.
  • src/utils/calculationUtils.ts, src/utils/reportUtils.ts: ignore or zero negative values already in storage (task, day, period, hours, revenue, report formatting).
  • src/components/ArchivedTaskRow.tsx, src/components/ArchiveEditDialog.tsx: an end before the start is flagged inline (role="alert", aria-invalid, aria-describedby), and Save/Add Task stays disabled until corrected. The day form rejects it through its zod schema, and Save Changes reopens a collapsed summary editor so the error is visible. Equal start and end times stay allowed, since 15-minute rounding can collapse a short task to zero length.
  • src/components/ui/scroll-time-picker.tsx: TimePicker accepts aria-invalid.
  • Tests added in TimeTracking.test.tsx, calculationUtils.test.ts, timeUtil.test.ts, ArchivedTaskRow.test.tsx, and ArchiveEditDialog.test.tsx.
  • Docs: CHANGELOG.md, README.md, README-EXT.md, AGENTS.md (new "Time Tracking Invariants" section), and agents/pitfalls.md.

Checklist

Documentation

  • Any notable changes added to the README.md
  • CHANGELOG.md updated accordingly
  • N/A — no README changes

General

  • Branch is up to date with main
  • No unrelated files included in this PR
  • Tested locally by invoking the pnpm test, pnpm lint, and pnpm build

Notes for Reviewers

  • The new endDay and adjustTaskTime context tests and the four archive validation tests fail without the fix and pass with it.
  • Negative values already saved by earlier versions are not rewritten. Calculations ignore them and displays show zero. A legacy negative archived task or day will block saving in the archive editor until its end time is corrected, which is intended.
  • TaskEditDialog (current-day task edit) does not show the inline validation. It relies on the adjustTaskTime clamp, so an end-before-start edit there saves as zero length. That could be a follow-up if you want the same inline error.
  • docs/TESTING.md, agents/testing.md, and docs/CI_CD.md carry test counts that were already stale. I left them alone.

Generated by Claude Code

endDay rounded the end time to 15 minutes while a running task's start was
unrounded, so the rounded end could precede the task start. Clamp endDay to
the latest recorded moment, route all duration subtraction through a
zero-floored elapsedMs helper, and ignore legacy negative values in
calculations and formatters.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UqjLGeuTJHemDQZo6PbAja
ArchivedTaskRow, the ArchiveEditDialog Add Task form, and the day summary
form now flag an end before the start inline and block saving. Adds
isEndBeforeStart/END_BEFORE_START_MESSAGE, documents the invariant in
AGENTS.md, pitfalls, README, README-EXT, and CHANGELOG.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UqjLGeuTJHemDQZo6PbAja
@github-actions github-actions Bot added automation For items related to release/documentation/workflow automations documentation Improvements or additions to documentation frontend labels Oct 19, 2026
@cloudflare-workers-and-pages

Copy link
Copy Markdown

Deploying timetrackerpro with  Cloudflare Pages  Cloudflare Pages

Latest commit: 52f5495
Status: ✅  Deploy successful!
Preview URL: https://6b814965.timetrackerpro.pages.dev
Branch Preview URL: https://fix-negative-durations.timetrackerpro.pages.dev

View logs

@github-project-automation github-project-automation Bot moved this to Backlog in Timetraked Oct 19, 2026
@AdamJ AdamJ added this to Timetraked Oct 19, 2026
@AdamJ AdamJ self-assigned this Oct 19, 2026
@AdamJ
AdamJ merged commit 00bdf01 into main Oct 19, 2026
3 checks passed
@github-project-automation github-project-automation Bot moved this from Backlog to Done in Timetraked Oct 19, 2026
@AdamJ
AdamJ deleted the fix/negative-durations branch October 19, 2026 13:43
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

automation For items related to release/documentation/workflow automations documentation Improvements or additions to documentation frontend

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

2 participants