
Zero-dependency time-clock punch rounding in JavaScript / TypeScript — round a worked duration in minutes to the nearest N-minute increment. This is the quarter-hour (15-minute) timesheet rounding that every payroll and time-tracking system has to implement, plus tenth-of-hour (6-minute) and any other increment.
One pure function, extracted verbatim from the production payroll core of Klock, a GPS time-tracking app for construction crews by Konstruction.
npm install @x1ee7/timeclock-roundingpnpm add @x1ee7/timeclock-rounding
# or: yarn add @x1ee7/timeclock-roundingESM + CommonJS + TypeScript types. No dependencies.
import { roundTime } from "@x1ee7/timeclock-rounding";
roundTime(127, 15, true); // → 120 (round 2h07 to the nearest quarter hour)
roundTime(128, 15, true); // → 135 (rounds up — past the half-way mark)
roundTime(100, 6, true); // → 102 (tenth-of-hour / 6-minute rounding)
roundTime(127, 15, false); // → 127 (rounding disabled — input unchanged)
roundTime(127, 1, true); // → 127 (increment <= 1 is a no-op)| Param | Description |
|---|---|
minutes |
Raw worked duration in minutes. |
roundingMinutes |
Increment to round to: 6, 10, 15, 30, … (<= 1 = no rounding). |
enabled |
When false, the input is returned unchanged. |
Rounding is symmetric (Math.round): an exact half rounds up. Rounding a
duration this way is mathematically the same as the classic "7-minute rule"
applied to a 15-minute grid — anything in the first 7 minutes of a quarter
rounds down, 8 minutes and up rounds up.
roundTime expresses every standard payroll rounding policy through one
roundingMinutes argument:
| Policy | roundingMinutes |
Effect |
|---|---|---|
| Quarter-hour / 15-minute / "7-minute rule" | 15 |
Nearest 0/15/30/45 |
| Tenth-of-hour | 6 |
Nearest 0.1h (6-minute blocks) |
| 10-minute | 10 |
Nearest 10 minutes |
| Half-hour | 30 |
Nearest 0/30 |
| No rounding (exact time) | 1 or enabled: false |
Raw minutes |
Because the function rounds to the nearest increment (not always up or always down), it is the neutral, both-directions method commonly used to stay compliant with timekeeping rules that prohibit systematically rounding in the employer's favour. It does not, by itself, constitute legal or payroll advice.
For a 15-minute grid the breakpoints are:
:00 – :07 → rounds down to :00
:08 – :22 → rounds to :15
:23 – :37 → rounds to :30
:38 – :52 → rounds to :45
:53 – :59 → rounds up to next :00
roundTime(minutes, 15, true) returns the minute value at the nearest of
those marks.
roundTime(minutes, 15, true). It returns the duration rounded to the
nearest quarter hour using symmetric (nearest, half-up) rounding.
On a 15-minute grid, the first 7 minutes round down and minutes 8–14 round up. Rounding to the nearest 15-minute increment produces exactly that behaviour, which is what this function does.
Pass 6 as the increment: roundTime(minutes, 6, true). Each tenth of an
hour is a 6-minute block.
Neither by default — it rounds to the nearest increment, with exact halves rounding up. That symmetric behaviour is the point: it does not bias for or against the employee.
Yes — pass enabled: false, or use an increment of 1. The raw minutes are
returned unchanged.
Maintained in the open by the team behind Konstruction. If it saved you from re-implementing timesheet rounding, consider sponsoring on GitHub.
MIT © konstruction.ca