WRLD CLOCK
Methodology
How every tool on WRLD CLOCK keeps time, in the terms its own engine uses. Every result on this page is computed by calling the engine when the site is built; the example inputs it is given are fixed constants declared in the page's source.
One rule for the timing engine
Every timer built on the timing engine — the countdown, the Pomodoro timer, the interval timer and the speech timer — stores an epoch anchor: a single instant, recorded when the timer starts. The display is derived from the difference between now and that anchor on each frame. Nothing accumulates per-tick deltas. A timer left running for an hour is therefore exactly as accurate as one that has just started, no matter how irregular the tick interval turns out to be.
The engine keeps two state shapes and nothing else. A countdown run is idle, running with an end instant, or paused with a balance; a count-up run is idle, running from an anchor, or paused with a total. Every other figure a timer shows — remaining time, elapsed time, progress, the band, the round — is derived from one of those records and the current instant at the moment of asking. That is why the tick rate is a matter of display and not of accuracy.
A worked example, using a fixed instant that is a constant in this page rather than the time you opened it. A focus interval of 25:00 started at that instant stores one number: the instant it should end. 10 minutes later the display reads 15:00, found by subtracting the current instant from the stored end. Pause at that point and the timer keeps the balance, 15:00, instead of an end instant. Resume 20 minutes after that and the engine sets a fresh end 45 minutes after the original start, so the display again reads 15:00. No part of this depends on how many ticks ran in between, or on whether any ran at all.
| Moment | What the engine stores | Display |
|---|---|---|
| Start | running — ends 25 minutes after start | 25:00 |
| 10 minutes in | running — the same end instant | 15:00 |
| Paused at 10 minutes | paused — balance 15:00 | 15:00 |
| Resumed at 30 minutes | running — ends 45 minutes after start | 15:00 |
| 40 minutes in | running — the same end instant | 05:00 |
The engine's count-up state does the same thing in the other direction. It stores the anchor it started from and shows now minus anchor; a pause keeps the elapsed total, and a resume moves the anchor so the total continues from where it stopped. From the same fixed instant, a count-up run reads 10:00 after 10 minutes. Paused there, it still reads 10:00 another 20 minutes later. Resumed at that point, its anchor moves to 20 minutes after the original start, so the display reads 10:00 and counts on from there. The speech timer's count-up option changes only what is displayed — time used rather than time left — and its bands are chosen the same way either way.
Two tools are not built on this engine. The stopwatch measures elapsed time against a monotonic browser clock, so it is unaffected by the system clock being corrected while it runs; the alarm is scheduled inside its page. The section on where the tools stop says what follows from that. The guide How the timers stay accurate takes the anchor rule through a reload as well.
How the display rounds
Seconds are rounded up. A fresh 25:00 timer reads 25:00, and a few hundred milliseconds into the run it still reads 25:00 rather than ticking down to the next second early. The display changes only once a whole second has gone.
Negative values — the speech timer past zero — are rendered with a leading minus and rounded away from zero for the same reason: the engine's clock formatter renders a talk 1 minute 30 seconds over as -01:30. The speech timer's own readout presents that same balance as the amount over, counting upward with a plus sign, so the stage shows +01:30. The browser tab title uses the clock string followed by the phase label, so the anchor example above would show as 15:00 · Focus while the tab was in the background.
| Milliseconds remaining | Clock string |
|---|---|
| 25:00 exactly | 25:00 |
| 400 ms short of it | 25:00 |
| 1 second short of it | 24:59 |
| 1 ms short of an hour | 01:00:00 |
| 1 second short of an hour | 59:59 |
| 1 ms | 00:01 |
| zero | 00:00 |
| 400 ms past zero | -00:01 |
| 1 minute 30 seconds past zero | -01:30 |
Two consequences are worth knowing when you read a display. Hours appear only once there is at least one of them, so a readout drops from three groups to two as a long run passes the hour; the countdown tool is the exception and always shows hours, so its default duration reads 00:05:00 rather than 05:00. And the plain-language formatter used for announcements rounds to the nearest second rather than up: 400 ms is 0 seconds in words, and the same instant that the clock shows as 25:00 is announced as 25 minutes.
Countdown: a duration or a target instant
Duration mode counts a length of time. The default is 05:00 — 5 minutes — and it is a starting point, not a limit. Settings are normalised before they run: a duration below 1 second is raised to 1 second, and anything above the ceiling is held at it. Asking for 1000 hours yields 99:00:00, which is 99 hours. The message shown under the clock is cut at 120 characters.
Date-and-time mode parses a plain datetime-localvalue in the viewer's own time zone. A countdown that spans a daylight-saving change is therefore short or long by exactly one hour — which is what a wall clock actually does. A time that does not exist because the clocks sprang forward normalises to the following instant, matching the platform's own resolution, and a date that overflows the calendar, such as the thirty-first of a thirty-day month, is rejected rather than rolled into the next month. The parser checks the shape of the value and the calendar, not the zone, so the verdicts below are the same wherever the page is built:
| Target value | What it is | Verdict |
|---|---|---|
2026-12-25T09:00 | a date and a time | accepted |
2026-12-25 09:00 | a space instead of the T | accepted |
2026-12-25T09:00:30 | with seconds | accepted |
2026-02-31T09:00 | the thirty-first of February | rejected |
2026-13-01T09:00 | a thirteenth month | rejected |
25/12/2026 09:00 | a day-first date | rejected |
A rejected target does not break the tool: normalisation keeps the typed value out of the settings and the mode falls back to duration, so asking for target mode with an empty target yields durationmode. In duration mode what is stored is the instant the countdown should reach zero; in date-and-time mode it is the typed wall-clock string, parsed afresh in the device's zone whenever the page needs the instant. The engine's figure for a target is simply that instant minus now, and it goes negative once the target has passed; the countdown's readout holds at zero rather than counting past it. Counting past zero is the speech timer's job, and the engine exposes it as an option that the countdown does not take. The guide Counting down to a date across daylight saving works through the one-hour effect.
Pomodoro: phases chained from their ends
The pattern is the widely used one: a fixed focus interval, a short break after each interval, and a longer break after every 4th. The defaults are 25 minutes of focus, 5 minutes for the short break and 15 minutes for the long break, with a session goal of 8 focus intervals; every value is configurable. The opening phases of a default session run Focus, Short break, Focus, Short break, Focus, Short break, Focus, Long break. The estimated wall-clock length of the whole default session, breaks included, is 4 hours 5 minutes; the session ends on its last focus interval, so no break is counted after it.
When a phase ends, the next phase is chained from the previous phase's end instant, not from the moment the tick noticed. A hundred consecutive phases therefore end exactly where arithmetic says they should, with no accumulated tick latency. Laid out from the start instant, the first 8 phases of a default session occupy 2 hours 10 minutes:
| # | Phase | Length | Starts | Ends |
|---|---|---|---|---|
| 1 | Focus | 25:00 | 00:00 | 25:00 |
| 2 | Short break | 05:00 | 25:00 | 30:00 |
| 3 | Focus | 25:00 | 30:00 | 55:00 |
| 4 | Short break | 05:00 | 55:00 | 01:00:00 |
| 5 | Focus | 25:00 | 01:00:00 | 01:25:00 |
| 6 | Short break | 05:00 | 01:25:00 | 01:30:00 |
| 7 | Focus | 25:00 | 01:30:00 | 01:55:00 |
| 8 | Long break | 15:00 | 01:55:00 | 02:10:00 |
Rolling a session forward crosses as many phase boundaries as the elapsed time demands, and the result is identical whether the roll happens on a regular tick or after the tab has been in the background for twenty minutes. Run through the engine: a default session started at the page's fixed instant and rolled forward in one step to 1 hour 10 minutes later reports 4 boundaries crossed — at 25:00, 30:00, 55:00, 01:00:00 after the start — and lands in a Focus phase with 2 focus intervals complete and 15:00 remaining. The remaining figure comes from the chained end instant, so it is the same whether the page ticked every quarter-second through those 1 hour 10 minutes or not at all.
With auto-advance off, the next phase is queued at its full length and paused until you start it. Skip phase abandons the current phase and queues the next one the same way; a skipped focus interval counts as completed, which is what moves the long-break cadence along.
Settings are normalised before a session starts, and the bounds are the engine's rather than the form's. Asking for a focus interval of 1 second gives 5 seconds; asking for a break of 10 hours gives 4 hours; a long-break cadence of 1 is raised to 2, and a goal of 100 intervals is lowered to 24. The guide Pomodoro intervals as the engine runs them estimates the length of two user-set configurations as well as the default.
Interval timer: a compiled plan
A session is compiled into a flat plan of steps — prepare, work, rest, cool down — each with a cumulative offset from the start instant. The running timer then answers “where am I?” with a single subtraction against the stored start epoch, which is what makes an eight-round session end exactly on time rather than a few hundred milliseconds late. Prepare and cool-down appear only when their length is above zero, and the rest after the final round is dropped: a trailing rest with nothing left to recover for is dead time.
The defaults are 10 seconds to get ready, 40 seconds of work, 20 seconds of rest, 1 minute of cool-down and 8 rounds, each of which you can change. That compiles to 17 steps: one get ready, 8 work, 7 rest and one cool down. The whole session lasts 8 minutes 50 seconds, of which 5 minutes 20 seconds is work. 2 minutes into the default session the position is Rest · round 2 of 8 with 00:10 left in that step, and 2 rounds are complete. The compiled plan for the defaults, offsets included:
| # | Step | Length | Starts | Ends |
|---|---|---|---|---|
| 1 | Get ready | 00:10 | 00:00 | 00:10 |
| 2 | Work · round 1 of 8 | 00:40 | 00:10 | 00:50 |
| 3 | Rest · round 1 of 8 | 00:20 | 00:50 | 01:10 |
| 4 | Work · round 2 of 8 | 00:40 | 01:10 | 01:50 |
| 5 | Rest · round 2 of 8 | 00:20 | 01:50 | 02:10 |
| 6 | Work · round 3 of 8 | 00:40 | 02:10 | 02:50 |
| 7 | Rest · round 3 of 8 | 00:20 | 02:50 | 03:10 |
| 8 | Work · round 4 of 8 | 00:40 | 03:10 | 03:50 |
| 9 | Rest · round 4 of 8 | 00:20 | 03:50 | 04:10 |
| 10 | Work · round 5 of 8 | 00:40 | 04:10 | 04:50 |
| 11 | Rest · round 5 of 8 | 00:20 | 04:50 | 05:10 |
| 12 | Work · round 6 of 8 | 00:40 | 05:10 | 05:50 |
| 13 | Rest · round 6 of 8 | 00:20 | 05:50 | 06:10 |
| 14 | Work · round 7 of 8 | 00:40 | 06:10 | 06:50 |
| 15 | Rest · round 7 of 8 | 00:20 | 06:50 | 07:10 |
| 16 | Work · round 8 of 8 | 00:40 | 07:10 | 07:50 |
| 17 | Cool down | 01:00 | 07:50 | 08:50 |
Reading a position off that plan is the subtraction the header describes. A step owns the instants from its start offset up to, but not including, its end offset, so at exactly 00:10 the get-ready step is over and the first work step has begun; at the final offset, 08:50, the engine reports the last step with nothing remaining and the session complete.
| Elapsed | Position | Left in step | Rounds done |
|---|---|---|---|
00:00 | Get ready | 00:10 | 0 |
00:10 | Work · round 1 of 8 | 00:40 | 0 |
02:00 | Rest · round 2 of 8 | 00:10 | 2 |
05:00 | Rest · round 5 of 8 | 00:10 | 5 |
08:50 | Cool down — complete | 00:00 | 8 |
The engine can also list the step boundaries crossed between two elapsed readings, in order — the primitive needed to notice every boundary that passed while a page was not ticking. Between the start of the default plan and 2 minutes in, it lists 4 boundaries: Get ready, Work · round 1 of 8, Rest · round 1 of 8, Work · round 2 of 8.
Forgiving parsing and strict normalisation meet here. A preset link of ?work=banana&rest=30&rounds=120&prep=0 keeps only what it can read: the work token is ignored and the default 40 seconds stands, the rest becomes 30 seconds, the round count is out of range and is ignored so 8 rounds stand, and the zero prepare is honoured. The result compiles to 16 steps beginning with work, because a prepare of 0 seconds is left out of the plan. Normalisation also bounds direct input: 500 rounds becomes 99, a work interval of zero becomes 1 second, and a rest of 2 hours becomes 1 hour. The guide Interval timer rounds and phases reads positions at several more elapsed values.
Speech timer: bands from remaining time
A speaker watches one thing: how much room is left. The timer therefore reports a band — On time, Wrap up, Final minute, Over time — chosen purely from the remaining milliseconds, and every band carries a text label as well as a colour so the signal survives colour blindness and a washed-out projector. The defaults are a 20:00 talk with wrap-up at 05:00 remaining and the final band at 01:00; all three are yours to change.
Thresholds are inclusive. Halfway through the default talk the band is On time; at exactly 05:00 remaining it is Wrap up; at exactly 01:00 it is Final minute; at zero it is Over time, and 1 minute 30 seconds past zero it is still Over time with the readout showing +01:30. The progress bar stays full once the talk is over rather than overflowing. The whole band table for the defaults, with the readout and the progress bar's fill at each point:
| Remaining | Band | Readout | Progress |
|---|---|---|---|
20:00 | On time | 20:00 | 0% |
10:00 | On time | 10:00 | 50% |
05:01 | On time | 05:01 | 75% |
05:00 | Wrap up | 05:00 | 75% |
01:01 | Wrap up | 01:01 | 95% |
01:00 | Final minute | 01:00 | 95% |
00:01 | Final minute | 00:01 | 100% |
00:00 | Over time | 00:00 | 100% |
-01:30 | Over time | +01:30 | 100% |
The wrap-up threshold can never sit inside the final band. Settings that ask for wrap-up at 00:30 with the final band at 01:00 are normalised so that wrap-up begins at 01:00. Count-up mode shows time used instead of time left; the bands are chosen the same way either way. The talk length itself is bounded: asking for zero gives 10 seconds, with the wrap-up threshold pulled in to 00:10 and the final one to 00:10 so both still fit inside it, and asking for 100 hours gives 8 hours. The guide Speech timer warning bands covers choosing the thresholds and reading the overtime figure.
Presets in the query string
Every timer built on the timing engine can be configured entirely from the query string, so a coach, teacher or conference organiser can hand out a bookmark instead of setup instructions. Parsing is deliberately forgiving about form and strict about validity: anything it cannot understand is ignored and the default is kept, so a mangled link still opens a working timer.
A duration token may be compound, clock-style or a bare number. 1h30m15s parses to 01:30:15; 05:00 to 05:00; the bare 90 is read as seconds by the interval timer, giving 01:30, and as minutes by the others, giving 01:30:00. ninety parses to nothing, so the default stands. Tokens above the ceiling are held at it: 500h becomes 100 hours. The parser run over a dozen tokens, once with the bare-number unit the countdown, focus and speech timers use and once with the interval timer's:
| Token | Bare numbers as minutes | Bare numbers as seconds |
|---|---|---|
25m | 25:00 | 25:00 |
90s | 01:30 | 01:30 |
1h30m15s | 01:30:15 | 01:30:15 |
05:00 | 05:00 | 05:00 |
1:30:00 | 01:30:00 | 01:30:00 |
90 | 01:30:00 | 01:30 |
1.5 | 01:30 | 00:02 |
␣25M␣ | 25:00 | 25:00 |
ninety | ignored — default kept | ignored — default kept |
-5 | ignored — default kept | ignored — default kept |
5m30 | ignored — default kept | ignored — default kept |
500h | 100:00:00 | 100:00:00 |
Three things in that table are easy to misread. Case and surrounding spaces are stripped before parsing, so the padded upper-case token is read like its tidy sibling. A unit suffix always wins over the bare number rule, so the same 25m means the same thing to every timer; only an unsuffixed number changes meaning between them. And a token with a trailing unsuffixed part, a negative, or a word is not a near miss that gets guessed at — it is ignored, and the default is kept.
The links the timers produce for their own defaults are ?work=25m&break=5m&long=15m&every=4&goal=8&auto=1 for the focus timer, ?prepare=10s&work=40s&rest=20s&rounds=8&cooldown=1m for the interval timer, ?d=20m&warn=5m&final=1m&mode=down for the speech timer and ?d=5m for the countdown. Tokens are written back in the shortest form that round-trips, so 1:30:00 is shared as 1h30m. The guide Shareable timer links lists every parameter name each timer accepts.
Persistence: epochs, never seconds left
Running state is written to this browser's storage as epochs, never as “seconds left”, so a reload picks the timer up exactly where the wall clock says it should be — including reloads that happen while the phone was in a pocket. Each saved envelope is versioned and records the instant it was saved, and that instant is checked against the clock before anything is restored. An envelope older than 12 hours is discarded, and so is one whose saved instant lies further ahead of the clock than the engine tolerates. Run through the engine with this page's fixed instant as the clock: an envelope saved 1 hour earlier is kept; one saved 12 hours 1 minute earlier is discarded; one dated 2 hours ahead is discarded. A discarded envelope opens the timer idle rather than resuming something stale.
| Envelope saved | Verdict |
|---|---|
| 1 hour earlier | kept |
| 12 hours earlier — exactly the limit | kept |
| 12 hours 1 minute earlier | discarded |
| 30 minutes ahead of the clock | kept |
| 1 hour ahead of the clock — exactly the tolerance | kept |
| 1 hour and 1 ms ahead of the clock | discarded |
| 2 hours ahead of the clock | discarded |
Both edges are the engine's verdicts, and the rows above mark where they fall: an envelope saved exactly 12 hours earlier is kept; one dated 1 hour ahead of the clock is kept, and one dated 1 ms further ahead is discarded. The forward figure is not read from the engine's source, where that bound is private: the page finds it by asking the engine for the largest lead it will still restore, so a change to the bound changes this page with it. Beyond either edge the envelope is dropped and the timer opens idle. Before the age is even considered, the envelope has to decode: the version must be the one the engine writes, the saved instant must be a finite number, and the state inside must pass the timer's own validator.
| Stored text | Verdict |
|---|---|
| a running focus interval saved by the engine itself | restored |
| the same envelope with its version number changed | rejected |
| the same envelope with no saved-at instant | rejected |
| a running state with no end instant | rejected |
| text that is not JSON at all | rejected |
| an empty string | rejected |
Storage keys name the timer and the envelope version — the 4 in use are wrldclock.timer.pomodoro.v1, wrldclock.timer.speech.v1, wrldclock.timer.interval.v1, wrldclock.timer.countdown.v1. The persistence helpers are pure — they take and return strings — and the timer components own the storage calls. Nothing in the envelope leaves this browser.
The day of the week
The calendar tool is proleptic Gregorian and computed with integer arithmetic — Sakamoto's weekday algorithm for the weekday and Julian Day Numbers for day counts — so it is independent of the platform date object, the local time zone and the two-digit-year quirk. A date maps to the same weekday whoever runs it, whenever they run it.
Leap years follow the full Gregorian rule: divisible by four, except centuries, unless divisible by four hundred. Run through the engine: 2000: leap; 1900: not leap; 2024: leap. Day counts are differences of Julian Day Numbers: from Saturday, January 1, 2000 to Thursday, January 1, 2026 is 9,497 days. Adding 2 days to 2024-02-28 gives 2024-03-01, while the same step from 2023-02-28 gives 2023-03-02, because February has 29 days in the first year and 28 in the second.
The weekday itself is a remainder: Sakamoto's algorithm folds the year, its leap-day count and a per-month offset into one sum and takes it modulo seven, with Sunday as zero. Four fixed dates run through it — including the date this page was last reviewed:
| Date | Index | Weekday | Day of year | Year |
|---|---|---|---|---|
1776-07-04 | 4 | Thursday | 186 | leap |
2000-02-29 | 2 | Tuesday | 60 | leap |
2026-09-30 | 3 | Wednesday | 273 | common |
2035-03-02 | 5 | Friday | 61 | common |
The same arithmetic lays out the calendar grid. September 2026 has 30 days and begins on a Tuesday, so its Sunday-first grid of 42 cells opens with 2 spill days from the previous month, runs from 2026-08-30 to 2026-10-10, and is rectangular whatever the month. Stepping the month forward by 4 rolls the year as needed and lands on January 2027. The traditional Monday's Child rhyme is keyed by the same index, so for Wednesday, September 30, 2026, a Wednesday, the tool shows the line “full of woe” — a folk rhyme, not a horoscope.
For dates before a country adopted the Gregorian calendar, the calculator gives the Gregorian weekday, which is the modern convention; the day of the week tool carries a note on very old dates. The guide How the day of the week is worked out walks through the algorithm step by step.
Where the tools stop
These behaviours are described here, not simulated. The alarm is scheduled inside its page, so the tab has to stay open for it to sound, and phones and laptops that fall asleep can delay or suppress the tone entirely. What the anchors guarantee is narrower and exact: whenever a tick does run, the display is correct for that instant, and a reload resumes from the stored epochs.
The same line applies to the four engine timers. The arithmetic above says what the display will read at any instant; it says nothing about whether a cue sounds at that instant, which depends on the device staying awake and the tab staying open. The stopwatch sits outside the engine and measures against a monotonic browser clock, so it does not take part in the saved-envelope mechanism either.
The world clock and the time-zone converter format each moment with the IANA time-zone data shipped with your browser, daylight saving included. For anything consequential, verify the time against the authoritative source before relying on it.
The guides
Each mechanism above has a guide of its own, written in the same terms and with its figures computed the same way. In reading order:
- How the timers stay accurate — Why every timer built on the timing engine derives its display from a stored epoch anchor rather than counting ticks, and what that means after a reload.
- Counting down to a date across daylight saving — How the countdown's date-and-time mode reads the target in your own time zone, and why a count that spans a clock change is short or long by exactly one hour.
- Pomodoro intervals as the engine runs them — The default focus, short-break and long-break lengths, how the long-break cadence works, and why each phase is chained from the previous phase's end instant.
- Interval timer rounds and phases — How a session of work and rest rounds compiles into a flat plan with cumulative offsets, and how the timer answers where it is with one subtraction.
- Speech timer warning bands — How the speech timer chooses the on-time, wrap-up, final and over-time bands purely from the remaining time, and how over time is shown.
- Shareable timer links — The query-string presets the four engine timers accept, the duration token forms they understand, and why a mangled link still opens a working timer.
- How the day of the week is worked out — The integer arithmetic behind the day-of-the-week calculator: the proleptic Gregorian calendar, the leap-year rule, and day counts between dates.
The guides index lists them with the tools they belong to.
Last reviewed , against the engine as built that day. The worked examples use the fixed instant and dates declared in this page's source, so a rebuild reproduces every figure.
Everything here runs in your browser: the timers keep time on this device's own clock, settings travel in the URL, and running state stays in this browser's storage. The guides take each mechanism in turn.