Skip to content

fix(windows): use GetTickCount64 to prevent overflow after 49.7 days#76

Merged
ErikBjare merged 1 commit into
ActivityWatch:masterfrom
TimeToBuildBob:fix/windows-tick-count-overflow
Feb 27, 2026
Merged

fix(windows): use GetTickCount64 to prevent overflow after 49.7 days#76
ErikBjare merged 1 commit into
ActivityWatch:masterfrom
TimeToBuildBob:fix/windows-tick-count-overflow

Conversation

@TimeToBuildBob

@TimeToBuildBob TimeToBuildBob commented Feb 27, 2026

Copy link
Copy Markdown
Contributor

Summary

  • GetTickCount returns a 32-bit DWORD that wraps at 2^32 ms (~49.7 days of uptime)
  • After wrapping, the idle time calculation produces incorrect results
  • Switched to GetTickCount64 which returns a 64-bit value with no practical overflow
  • Added wraparound handling for dwTime from GetLastInputInfo (always 32-bit per Windows API)

Technical details

The seconds_since_last_input() function computed GetTickCount() - dwTime. After 49.7 days:

  • GetTickCount() wraps to near 0
  • dwTime (last input) could still be a large number
  • Result: negative value (displayed as huge idle time)

The fix uses GetTickCount64() and compares only the lower 32 bits against dwTime, handling the wrap edge case.

Note: GetTickCount64 requires Windows Vista+ (2007), which should be a safe baseline in 2026.

Test plan

Fixes #16


Important

Switches to GetTickCount64 in aw_watcher_afk/windows.py to prevent overflow after 49.7 days and handles dwTime wraparound.

  • Behavior:
    • Replaces GetTickCount with GetTickCount64 in aw_watcher_afk/windows.py to prevent overflow after 49.7 days.
    • Handles wraparound for dwTime from GetLastInputInfo in seconds_since_last_input().
  • Functions:
    • Adds _getTickCount64() to retrieve 64-bit tick count.
    • Modifies seconds_since_last_input() to use 64-bit tick count and handle 32-bit wraparound.
  • Misc:
    • Requires Windows Vista+ for GetTickCount64.

This description was created by Ellipsis for 44b9ff6. You can customize this summary. It will automatically update as commits are pushed.

GetTickCount returns a DWORD (32-bit) that wraps at 2^32 ms (~49.7 days
of uptime). After wrapping, the idle time calculation would produce
incorrect values (either negative or huge numbers).

Switch to GetTickCount64 which returns a 64-bit value with no practical
overflow limit. Also handle the 32-bit wraparound of dwTime from
GetLastInputInfo (which always returns DWORD per the Windows API).

Fixes ActivityWatch#16

@ellipsis-dev ellipsis-dev Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Important

Looks good to me! 👍

Reviewed everything up to 44b9ff6 in 6 seconds. Click for details.
  • Reviewed 53 lines of code in 1 files
  • Skipped 0 files when reviewing.
  • Skipped posting 0 draft comments. View those below.
  • Modify your settings and rules to customize what types of comments Ellipsis leaves. And don't forget to react with 👍 or 👎 to teach Ellipsis.

Workflow ID: wflow_GXWUCFcQNivrQgT1

You can customize Ellipsis by changing your verbosity settings, reacting with 👍 or 👎, replying to comments, or adding code review rules.

@greptile-apps

greptile-apps Bot commented Feb 27, 2026

Copy link
Copy Markdown

Greptile Summary

This PR fixes a critical bug where GetTickCount() overflows after 49.7 days of system uptime, causing incorrect idle time calculations. The fix switches to GetTickCount64() which returns a 64-bit value with no practical overflow risk.

Key Changes:

  • Replaced 32-bit GetTickCount() with 64-bit GetTickCount64() in _getTickCount64() function
  • Added wraparound handling for the 32-bit dwTime value from GetLastInputInfo() API
  • Compares lower 32 bits of 64-bit tick count against 32-bit last input tick to detect wraparound
  • Calculates time difference correctly across the 32-bit boundary

Implementation Notes:

  • The wraparound logic assumes at most one 32-bit wrap since last input (handles up to 49.7 days of inactivity)
  • Requires Windows Vista+ (2007), which is a safe baseline in 2026
  • The fix follows Microsoft's recommended approach for handling mixed 32/64-bit tick counts

Confidence Score: 5/5

  • This PR is safe to merge with no risk - it fixes a critical overflow bug with a well-tested Windows API approach
  • The fix is minimal, focused, and follows Microsoft's documented approach for GetTickCount64. The wraparound handling logic is correct for typical usage (assuming wraparound occurs at most once). The change has no impact on other platforms and requires Windows Vista+ which is universally available in 2026.
  • No files require special attention

Important Files Changed

Filename Overview
aw_watcher_afk/windows.py Replaces GetTickCount with GetTickCount64 to fix overflow after 49.7 days, adds wraparound handling for 32-bit dwTime from GetLastInputInfo

Last reviewed commit: 44b9ff6

@greptile-apps greptile-apps Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1 file reviewed, no comments

Edit Code Review Agent Settings | Greptile

@ErikBjare ErikBjare merged commit 2d4519c into ActivityWatch:master Feb 27, 2026
1 of 3 checks passed
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.

Will fail after 49.7 days of uptime on Windows

2 participants