From 2634f9de7b1228cd887b7cab880af8a795c77053 Mon Sep 17 00:00:00 2001 From: spokodev Date: Thu, 9 Jul 2026 16:16:44 +0100 Subject: [PATCH] fix(date): zero-pad milliseconds when formatting %N fractional seconds (#929) %N renders the fractional part of the second. The milliseconds returned by getMilliseconds() are the three most significant digits of that fraction and must be zero-padded to three digits before use, otherwise sub-100ms values lose their leading zeros: 50ms => strftime("%N") returned "500000000", expected "050000000" 5ms => strftime("%3N") returned "500", expected "005" Pad the milliseconds to three digits before slicing to the requested width. --- src/util/strftime.spec.ts | 9 +++++++++ src/util/strftime.ts | 2 +- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/src/util/strftime.spec.ts b/src/util/strftime.spec.ts index b629b6d98..bacefce51 100644 --- a/src/util/strftime.spec.ts +++ b/src/util/strftime.spec.ts @@ -87,6 +87,15 @@ describe('util/strftime', function () { expect(t(time, '%10N')).toBe('1290000000') expect(t(time, '%0N')).toBe('129000000') }) + it('should zero pad %N for sub-100ms fractional seconds', function () { + const time = new TestDate('2019-12-15 01:21:00.005') + expect(t(time, '%N')).toBe('005000000') + expect(t(time, '%3N')).toBe('005') + expect(t(time, '%6N')).toBe('005000') + const tens = new TestDate('2019-12-15 01:21:00.050') + expect(t(tens, '%N')).toBe('050000000') + expect(t(tens, '%2N')).toBe('05') + }) it('should format %p as upper cased am/pm', function () { expect(t(now, '%p')).toBe('PM') expect(t(then, '%p')).toBe('AM') diff --git a/src/util/strftime.ts b/src/util/strftime.ts index 8bf8b09d1..1d303c15f 100644 --- a/src/util/strftime.ts +++ b/src/util/strftime.ts @@ -98,7 +98,7 @@ const formatCodes: Record = { M: (d: LiquidDate) => d.getMinutes(), N: (d: LiquidDate, opts: FormatOptions) => { const width = Number(opts.width) || 9 - const str = String(d.getMilliseconds()).slice(0, width) + const str = padStart(String(d.getMilliseconds()), 3, '0').slice(0, width) opts.memoryLimit?.use(width - str.length) return padEnd(str, width, '0') },