Round a Time to the Nearest 15 Minutes in JavaScript

To round to the nearest quarter hour, call zdt.round({ smallestUnit: 'minute', roundingIncrement: 15 }). Part of Working with ZonedDateTime Objects.

Why this scenario is tricky

Rounding time by hand — converting to minutes, dividing, multiplying back — loses sub-minute precision and mishandles the top-of-hour rollover (14:53 should round up to 15:00, crossing the hour). Temporal's round takes an increment and a rounding mode and carries the rollover for you.

Rounding must carry the hourManual minute math drops the rolloverRounding must carry the hourMath.round(min/15)*1514:53 → 15:00 mishandledround({increment:15})carries into the hourround() handles the carry into hours and keeps the zone.

Minimal working solution

import { Temporal } from '@js-temporal/polyfill';
const t = Temporal.ZonedDateTime.from('2024-03-15T14:53:00[America/New_York]');
t.round({ smallestUnit: 'minute', roundingIncrement: 15 }).toString(); // 15:00

Round to 15 minincrement 15 on the minute unitRound to 15 min14:53roundincrement 1515:00

Full production version

import { Temporal } from '@js-temporal/polyfill';
// Always round up to the next slot for booking start times.
function ceilToSlot(t: Temporal.ZonedDateTime, minutes = 15) {
  return t.round({ smallestUnit: 'minute', roundingIncrement: minutes, roundingMode: 'ceil' });
}

Ceil to a slotroundingMode ceil for booking slotsCeil to a slottimeincrement nmode ceilnext slot

Verification snippet

Round to 15 Minutes assertionsKey cases assert correctlyAssertions that prove the edge case14:53 nearest15:0014:07 nearest14:00ceil 14:0114:15secondsdropped

Common pitfalls

Round to 15 Minutes pitfallsCommon mistakes and their fixesWrongRightMath.round(min/15)*15no hour carryround increment 15carries correctlyignore roundingModesurprising directionset roundingModeexplicit direction

Frequently Asked Questions

How do I round a time to the nearest 15 minutes?

Call zdt.round({ smallestUnit: 'minute', roundingIncrement: 15 }) on a Temporal.ZonedDateTime (or PlainTime). It rounds to the nearest quarter hour and carries into the hour when needed, so 14:53 becomes 15:00.

How do I always round up to the next slot?

Add roundingMode: 'ceil' to the round options. That makes any time that is not exactly on a boundary move up to the next 15-minute slot, which is what booking and scheduling systems usually want for start times.