induwara.lk
induwara.lkTime · Utility

Online Stopwatch with Lap Times and CSV Export

A fast, no-signup stopwatch that runs entirely in your browser. Millisecond precision, unlimited laps up to 1,000, keyboard shortcuts, and a one-click CSV download for the full lap table. Press the spacebar to start.

By Induwara AshinsanaUpdated May 11, 2026
Online stopwatchmillisecond precision
Ready
00:00.00

Elapsed time

SpaceStart / pauseLLapRReset

Laps

Press Start and then Lap to record split times. Use L on your keyboard for instant laps.

How it works

The stopwatch is built on two browser primitives: performance.now(), the W3C High Resolution Time API, and requestAnimationFrame, the standard render-synchronised callback. Together they give a clock that stays accurate even when the tab is backgrounded.

When you press Start, the tool records the currentperformance.now() value as the run's start timestamp. On every animation frame, the live elapsed time is computed as elapsed = accumulated + (now − start) and rendered to the screen. Because we store a single start timestamp rather than counting ticks, the elapsed value is always correct regardless of how many frames the browser actually delivered — background tabs, throttled windows, and reduced-motion users all see the same final reading.

When you press Pause, the elapsed time is folded into accumulated and the start timestamp is cleared. Resume starts a fresh interval that adds to the saved accumulator, so pauses are lossless and unlimited.

A Lap snapshots the current elapsed time as that lap's split. Each lap also stores its lap time— the difference between its split and the previous lap's split. The sum of all lap times equals the most recent split, by construction, so the table is self-checking.

The CSV export follows RFC 4180: CRLF line terminators, double-quoted fields where the content contains a comma or quote, and a UTF-8 BOM-free body. The file includes both formatted columns (HH:MM:SS.mmm) and raw millisecond columns so you can re-format the times in your spreadsheet of choice.

The on-screen readout truncates rather than rounds. A true reading of 999 ms is shown as 00:00.99, never 00:01.00 — a stopwatch that lies about completed time is a stopwatch nobody can trust for race timing.

Worked examples

Three sprint splits

Lap 1 at 3.000s · Lap 2 at 8.000s · Lap 3 at 9.500s

  1. Lap 1 split = 3.000s · lap = 3.000s (no prior split)
  2. Lap 2 split = 8.000s · lap = 8.000 − 3.000 = 5.000s
  3. Lap 3 split = 9.500s · lap = 9.500 − 8.000 = 1.500s
  4. Sum of lap times = 3.000 + 5.000 + 1.500 = 9.500s = final split ✓
  5. Fastest: lap 3 (1.500s) · Slowest: lap 2 (5.000s) · Average: 3.167s

One-hour boundary

Elapsed: 3,599,990 ms · Elapsed: 3,600,000 ms

  1. 3,599,990 ms → 59:59.99 (still under one hour, hours field hidden)
  2. 3,600,000 ms → 1:00:00.00 (rolls into the hours field)
  3. Precise view at the boundary: 00:59:59.990 → 01:00:00.000
  4. No frames lost across the rollover — performance.now() is monotonic.

Button-mash lap (edge case)

Lap 1 at 2.000s · Lap 2 at 2.000s (same instant)

  1. Lap 1 split = 2.000s · lap = 2.000s
  2. Lap 2 split = 2.000s · lap = 2.000 − 2.000 = 0.000s
  3. Lap 2 is recorded as the fastest (and shortest) lap.
  4. No NaN, no negative durations — clamped at zero by design.

Frequently asked questions

Sources & references

Related tools

Rate this tool
Be the first to rate

Comments & feedback

Spotted a bug or want an improvement? Tell us — our team reviews every comment, and good ideas get built. Comments are public and anonymous.

Found a bug, edge case, or want to suggest an improvement?

Email me at [email protected] — most fixes ship within 24 hours.