diff --git a/lib/utils.js b/lib/utils.js index bb4b8d6..08a0408 100755 --- a/lib/utils.js +++ b/lib/utils.js @@ -2,7 +2,7 @@ const { readdir, stat, unlink, symlink, lstat, readlink } = require('fs/promises') const { dirname, join } = require('path') -const { format } = require('date-fns') +const { format, addDays, addHours } = require('date-fns') function parseSize (size) { let multiplier = 1024 ** 2 @@ -53,11 +53,11 @@ function validateLimitOptions (limit) { } function getNextDay (start) { - return new Date(start + 24 * 60 * 60 * 1000).setHours(0, 0, 0, 0) + return addDays(new Date(start), 1).setHours(0, 0, 0, 0) } function getNextHour (start) { - return new Date(start + 60 * 60 * 1000).setMinutes(0, 0, 0) + return addHours(new Date(start), 1).setMinutes(0, 0, 0) } function getNextCustom (frequency) { diff --git a/package.json b/package.json index 3b19c67..283c0c5 100644 --- a/package.json +++ b/package.json @@ -28,6 +28,7 @@ }, "devDependencies": { "husky": "^9.0.11", + "mockdate": "^3.0.5", "pino": "^9.2.0", "snazzy": "^9.0.0", "standard": "^17.0.0-2", diff --git a/test/lib/utils.test.js b/test/lib/utils.test.js index 02c3a3d..990d236 100755 --- a/test/lib/utils.test.js +++ b/test/lib/utils.test.js @@ -5,6 +5,7 @@ const { writeFile, rm, stat, readlink, symlink } = require('fs/promises') const { join } = require('path') const { test } = require('tap') const { format } = require('date-fns') +const MockDate = require('mockdate') const { buildFileName, @@ -69,6 +70,66 @@ test('getNext()', async ({ same }) => { same(getNext(custom), Date.now() + custom, 'supports custom frequency and does not return start') }) +test('getNext() on dates transitioning from DST to Standard Time', async ({ same }) => { + // on these days the time rolls back 1 hour so there "are" 25 hours in the day + // genNext() should account for variable number of hours in the day + + // test two different timezones + const data = [ + { + tz: 'Europe/Berlin', + mockDate: '27 Oct 2024 00:00:00 GMT+0100' + }, + { + tz: 'America/New_York', + mockDate: '03 Nov 2024 00:00:00 GMT-0500' + } + ] + + for (const d of data) { + MockDate.set(d.mockDate) + process.env.TZ = d.tz + const today = new Date() + + same(getNext('daily'), startOfDay(addDays(today, 1)).getTime(), 'supports daily frequency') + same(getNext('hourly'), startOfHour(addHours(today, 1)).getTime(), 'supports hourly frequency') + const custom = 3000 + same(getNext(custom), Date.now() + custom, 'supports custom frequency and does not return start') + MockDate.reset() + process.env.TZ = undefined + } +}) + +test('getNext() on dates transitioning from Standard Time to DST', async ({ same }) => { + // on these days the time rolls forward 1 hour so there "are" 23 hours in the day + // genNext() should account for variable number of hours in the day + + // test two different timezones + const data = [ + { + tz: 'Europe/Berlin', + mockDate: '31 March 2024 01:00:00 GMT+0100' + }, + { + tz: 'America/New_York', + mockDate: '10 Nov 2024 01:00:00 GMT-0500' + } + ] + + for (const d of data) { + MockDate.set(d.mockDate) + process.env.TZ = d.tz + const today = new Date() + + same(getNext('daily'), startOfDay(addDays(today, 1)).getTime(), 'supports daily frequency') + same(getNext('hourly'), startOfHour(addHours(today, 1)).getTime(), 'supports hourly frequency') + const custom = 3000 + same(getNext(custom), Date.now() + custom, 'supports custom frequency and does not return start') + MockDate.reset() + process.env.TZ = undefined + } +}) + test('getFileName()', async ({ equal, throws }) => { const strFunc = () => 'my-func' throws(getFileName, 'throws on empty input')