Node.js · 07/19 7 min
Dates, timestamps and money in JS
Zero-based months, UTC vs local, seconds vs milliseconds, and why money is integer cents.
Timestamps: know the unit
| Source | Unit |
|---|---|
Date.now(), date.getTime() |
milliseconds |
Unix time, JWT exp/iat, most webhook headers |
seconds |
const ageSec = Math.floor(Date.now() / 1000) - Number(req.headers["x-timestamp"]);
if (Math.abs(ageSec) > 300) return res.status(400).end(); // 5-minute tolerance
Mixing them is off by a factor of 1000: everything looks "expired" or nothing ever does.
Months are zero-based
new Date(2024, 0, 31); // 31 January
d.getMonth() + 1; // human month number
d.getDay(); // day of WEEK (0 = Sunday), not day of month → getDate()
UTC vs local
new Date("2024-03-01"); // date-only string → parsed as UTC midnight
new Date("2024-03-01T00:00"); // date-time without offset → LOCAL midnight
d.toISOString(); // always UTC, ends in Z
d.getUTCMonth(); d.getMonth(); // UTC vs local; reports should pick one and stick to it
Grouping sales by day with getDate() on a server in another timezone shifts rows into the wrong bucket. Use the getUTC* family for server-side reports.
Date ranges
An "end date" of 2024-03-31 stored as midnight excludes everything after 00:00 that day. Use a half-open range:
{ createdAt: { $gte: start, $lt: dayAfter(end) } }
Money
0.1 + 0.2; // 0.30000000000000004
(1.005).toFixed(2); // "1.00" (1.005 is really 1.00499999…)
(19.99).toFixed(2) + 1; // "19.991" toFixed returns a STRING
- Store and compute in integer cents; format only at the edge:
(cents / 100).toFixed(2). - Apply discounts and tax with one explicit rounding step:
Math.round(cents * rate). - Sum line items as
price * qtyin cents, then round once, not per step.
Practise it now
Next in Node.js
Reading request input safely