Label the units. 2:30 reads as half past two just as easily as two and a half hours, so anywhere a duration could be mistaken for a clock time, write 2h 30m or 2 hr 30 min instead. Keep the HH:MM form only where the context makes it unmistakable — a video scrubber, a timesheet column with a header that says so — and never put a duration and a timestamp in the same column.
Key points
2:30can be read as a clock time;2h 30mcannot.- Use unit labels in lists and reports, where durations sit near timestamps.
- Keep HH:MM for media players and timesheet grids, where columns align.
- Give machines the ISO form with
<time datetime="PT2H30M">. Intl.DurationFormathandles units and plurals in every locale.
Table of Contents
Why HH:MM goes wrong
The problem is not that HH:MM is unclear in isolation. It is that the same notation already means something else. A colon between two numbers is how we write times of day, so the reader has to work out from context which one you mean — and in a dense table there often is no context.
It gets worse in three specific places. A duration under an hour, 0:45, looks like a broken clock time. A duration over 24 hours, 36:00, looks like nothing at all. And a row that shows both — started 09:15, took 2:30 — invites the reader to subtract two numbers that are not the same kind of quantity.
Where HH:MM still earns its place
Two contexts are strong enough to carry it. The first is media. Every video player on the web shows elapsed and total time with colons, and nobody misreads it, because a progress bar is unambiguous about what the number means.

That detail is the one worth copying. YouTube shows the compact colon form to the eye and ships a fully spelled‑out, unit‑labelled string to assistive technology. You do not have to choose between scannable and unambiguous; you can give each audience the form that suits it.
The second context is a grid of durations that get compared or added — a timesheet, a report of task times. Here HH:MM genuinely helps, because the colon acts as a decimal alignment point and a column of times lines up cleanly. Say so in the column header (“Duration”, not “Time”) and keep every value in that column the same kind of number.
Unit labels are the safe default
Everywhere else, spell out the units. GitHub Actions is a good model, because it has to show both kinds of number on the same row and never confuses them.

Two things are doing the work. The units are attached to the numbers, and a different icon precedes each kind of value, so you can tell a duration from a timestamp before you have read either. Note also that leading zeroes are dropped — 22s, not 00:22 — and that units the value does not need are simply omitted.
Decimal hours are a third option, for a different job
Time‑tracking tools tend to offer a choice. Harvest exposes exactly two settings for time display, decimal and hours_minutes, and is instructive about where it uses each: HH:MM appears on timesheets only, while reports and invoices always use decimal, for precision. Toggl Track has a comparable duration‑display setting on the profile page that changes formats across the app and its reports.
The split is the right one. Decimal hours (2.25) exist so that numbers can be multiplied by an hourly rate without anyone doing base‑60 arithmetic in their head. HH:MM exists so that a person can read a duration quickly. Pick per context, make it a user preference if your users bill by the hour, and never mix the two in one column — 2.25 and 2:15 are the same duration and look like different ones.
If you do offer that as a setting, it is a straightforward two‑state preference, which is a good use for a toggle or a segmented control depending on how many formats you support.
Let the platform format it
Since March 2025 you have not needed to hand‑roll any of this in JavaScript. Intl.DurationFormat reached Baseline “newly available” when Firefox 136 shipped it, joining Chrome 129 and Safari 16.4, and it does the units, the abbreviations and the plural rules for you in every locale.
const d = { hours: 2, minutes: 30 };
new Intl.DurationFormat("en", { style: "long" }).format(d); // "2 hours, 30 minutes"
new Intl.DurationFormat("en", { style: "short" }).format(d); // "2 hr, 30 min"
new Intl.DurationFormat("en", { style: "narrow" }).format(d); // "2h 30m"
new Intl.DurationFormat("en", { style: "digital" }).format(d); // "2:30:00"
Two things will catch you out. The digital style pads the seconds, so you get 2:30:00 rather than 2:30 unless you pass secondsDisplay: "auto". And it does not normalise: hand it { minutes: 90 } and you get 0:90:00, because carrying minutes into hours is still your job.
Whatever you render, give machines the unambiguous version too. HTML’s <time> element takes an ISO 8601 duration in its datetime attribute, which is the one form that can never be mistaken for a clock time:
<p>The concert will last for at least <time datetime="PT2H30M">2h 30m</time>.</p>
House rules worth writing down
- Match the unit to the plural. “1 minutes” is sloppy. Better still, do not hand‑roll it — some languages have up to six plural forms, which is precisely what
Intl.DurationFormatis for. - Pick one abbreviation set and stick to it. Microsoft’s style guide uses
d,h,min,sec,ms; the CLDR data behindIntl.DurationFormatuseshrfor hours. Either is defensible; using both on one screen is not. - Be specific. “A few minutes” tells the reader nothing and annoys them more than a number would. GOV.UK’s style guide writes durations longhand — “6 hours 30 minutes”.
- Drop units you do not need. Material’s long‑standing advice on data formats is H:MM:SS with hours or seconds omitted when they do not apply.
- Never round silently. If you display
1mfor a 63‑second job, say somewhere that the figure is rounded.
Checklist
- Could this number be read as a time of day? If yes, add units.
- Do durations and timestamps ever share a column or a line? Separate them, and mark them differently.
- Is there a
<time datetime>around it for machines? - Does the accessible name spell the units out, even if the visible text does not?
- Is every duration on the screen using the same format and the same abbreviations?
Most of this is a house‑style decision rather than a hard rule, and the failure mode is drift: three screens, three formats, none of them wrong on its own. The semantic half is checkable, though — our free site audit will flag dates and durations rendered as plain text with no <time> markup, alongside the other structure problems on the page. For the visual half, our design tools are a good place to start.



