Skip to content
AF
Interactive

“Today’s steps” is the most bug-prone number in a fitness app

It looks trivial and it is not. A civil day is only usually 24 hours long, so any daily total computed over a fixed UTC window is quietly wrong on the two days a year a timezone shifts. Pick a zone and a daylight-saving day below and watch it happen — every number computed live in your browser from its own timezone database.

Local day starts
8 Mar 2026, 00:00
= 8 Mar 2026, 08:00 UTC
Local day ends
9 Mar 2026, 00:00
= 9 Mar 2026, 07:00 UTC
UTC offset that day
UTC−08:00 → UTC−07:00
Length of this civil day
23 hours(not 24 — DST spring forward)

This civil day is 23 hours long, not 24. If your daily total queries a fixed [midnight, midnight+24h) UTC range, you just droppedan hour of this user’s data — the classic bug that makes step counts and streaks wrong twice a year. Store the local civil date, not just the instant.

Computed live in your browser from its own IANA timezone database — nothing here is a number we hardcoded.

Why this bites health apps specifically

In most software a mislabelled day is cosmetic. In a fitness app it corrupts the numbers users check obsessively: a step count that drops an hour reads as the app losing their walk, a streak that spans a DST night breaks when it shouldn’t, and a “daily average” computed over 23- and 25-hour days is subtly off forever. The user knows how far they walked; when your number disagrees, they trust the app less.

The full storage model — instant plus offset plus civil date, and how to recompute a day that a late-arriving sample makes stale — is in timezones and day boundaries. The broader “samples are late-arriving, not append-only” problem this is part of lives in incremental sync, and the test-data guide explains why a DST night belongs in your fixtures.

Frequently asked questions

Why isn't a day always 24 hours?
Because of daylight-saving transitions. On the day a zone springs forward, the clock skips an hour, so the civil day is 23 hours long; on the day it falls back, an hour repeats and the day is 25 hours. A daily total that assumes every day is a fixed 24-hour UTC window will include or drop an hour of a user's activity on exactly those two days a year, and the bug is invisible the rest of the time.
How should I store a daily total so this doesn't happen?
Store the instant (UTC) for each sample, the UTC offset in effect at that instant, and — where your product needs a per-day figure — the local civil date the sample belongs to. Compute 'today' against the user's local midnight, resolved through a real timezone database, not against a fixed UTC range. UTC alone loses the information you need to answer 'which day was this'; local time alone loses the ability to order events. You need both.
Does this demo use data you collected about timezones?
No. Everything on this page is computed in your browser from the platform's own IANA timezone database via the built-in Intl API. There are no timezone facts we hardcoded, so nothing here can be stale or wrong about a specific zone — your device is the source.

A free interactive demo from AIFitnessAPI. Independent and not sponsored — link it if it helps you explain this to someone.