有没有办法在仅使用 UTC 日期的情况下设置本地时区的小时/分钟?

问题描述 投票:0回答:3

我想在 Node.js 后端应用程序中使用 UTC 日期,但是,我需要能够在本地/用户指定的时区中设置时间(小时和分钟)。

我正在寻找纯 JS 或使用

dayjs
的解决方案。我不是在寻找使用
moment
的解决方案。

看起来使用

dayjs
我可以很容易地解决这个问题,但是,我找不到一种方法来完成这个任务。

我可以通过使用

dayjs.utc()
或使用
dayjs.tz(someDate, 'Etc/UTC')
来使用 UTC 时区。

使用

dayjs.utc()
时,我无法为任何东西使用/指定其他时区,因此我找不到方法来告诉
dayjs
我想在特定(非UTC)时区设置小时/分钟。

使用

dayjs.tz()
时,我仍然无法定义要设置为特定日期的时间时区。

纯 JS 示例

我的区域设置时区是

Europe/Slovakia
(CEST = UTC+02,带 DST,CET = UTC+1,不带 DST),但是,我希望它适用于任何时区。

// Expected outcome
// old: 2022-10-29T10:00:00.000Z
// new time: 10h 15m CEST
// new: 2022-10-29T08:15:00.000Z

// Plain JS
const now = new Date('2022-10-29T10:00:00.000Z')
const hours = 10
const minutes = 15
now.setHours(10)
now.setMinutes(15)

// As my default timezone is `Europe/Bratislava`, it seems to work as expected
console.log(now)
// Output: 2022-10-29T08:15:00.000Z

// However, it won't work with timezones other than my local timezone

(几乎)解决方案

更新:我在这个答案中发布了一个工作功能。

以下功能似乎适用于大多数测试用例,但是,对于我已知的 6 4 个案例,它失败了(非常感谢任何帮助):

  • [DST 到 ST]
    now
    在双小时之前为 DST,
    newDate
    在双小时期间为 ST;
  • [DST 至 ST]
    now
    双小时期间为 DST,双小时期间
    newDate
    ST;
  • [DST 至 ST]
    now
    双小时内为 ST,双小时内
    newDate
    为 DST;
  • [DST 转 ST]
    now
    在两小时后为 ST,
    newDate
    在两小时内为 DST;
  • [ST 到 DST] 跳过小时前的 ST 中的
    now
    ,跳过的小时中的 ST 中的
    newDate
  • [ST 到 DST] 跳过一小时后的 DST 中为 now
    ,跳过一小时后的 ST 中为 
    newDate
  • 我认为唯一缺少的部分是找到一种方法来检查非 UTC 时区中的特定日期是否属于双小时。我所说的
双时

是指将夏令时更改为标准时间造成的情况,即将时钟调慢一小时(例如,凌晨3点到凌晨2点→双时是在02:00:00.000

02:59:59.999
之间,这两种情况都会发生在夏令时和标准时间) .

/** * Set time provided in a timezone * * @param {Date} [dto.date = new Date()] Date object to work with * @param {number} [dto.time.h = 0] Hour to set * @param {number} [dto.time.m = 0] Minute to set * @param {number} [dto.time.s = 0] Second to set * @param {number} [dto.time.ms = 0] Millisecond to set * @param {string} [dto.timezone = 'Europe/Bratislava'] Timezone of `dto.time` * * @return {Date} Date object */ function setLocalTime(dto = { date: new Date(), // TODO: Rename the property to `{h, m, s, ms}`. time: {h: 0, m: 0, ms: 0, s: 0}, timezone: 'Europe/Bratislava' }) { const defaultTime = {h: 0, m: 0, ms: 0, s: 0} const defaultTimeKeys = Object.keys(defaultTime) // src: https://stackoverflow.com/a/44118363/3408342 if (!Intl || !Intl.DateTimeFormat().resolvedOptions().timeZone) { throw new Error('`Intl` API is not available or it does not contain a list of timezone identifiers in this environment') } if (!(dto.date instanceof Date)) { throw Error('`date` must be a `Date` object.') } try { Intl.DateTimeFormat(undefined, {timeZone: dto.timezone}) } catch (e) { throw Error('`timezone` must be a valid IANA timezone.') } if ( typeof dto.time !== 'undefined' && typeof dto.time !== 'object' && dto.time instanceof Object && Object.keys(dto.time).every(v => defaultTimeKeys.indexOf(v) !== -1) ) { throw Error('`time` must be an object of `{h: number, m: number, s: number, ms: number}` format, where numbers should be valid time values.') } dto.time = Object.assign({}, defaultTime, dto.time) const getTimezoneOffsetHours = ({date, localisedDate, returnNumber, timezone}) => { let offsetString if (localisedDate) { offsetString = localisedDate.find(i => i.type === 'timeZoneName').value.match(/[\d+:-]+$/)?.[0] } else { offsetString = new Intl .DateTimeFormat('en-GB', {timeZone: timezone, timeZoneName: 'longOffset'}) .formatToParts(date) .find(i => i.type === 'timeZoneName').value.match(/[\d+:-]+$/)?.[0] } return returnNumber ? offsetString.split(':').reduce((a, c) => /^[+-]/.test(c) ? +c * 60 : a + +c, 0) : offsetString } const pad = (n, len) => `00${n}`.slice(-len) let [datePart, offset] = dto.date.toLocaleDateString('sv', { timeZone: dto.timezone, timeZoneName: 'longOffset' }).split(/ GMT|\//) offset = offset.replace(String.fromCharCode(8722), '-') const newDateWithoutOffset = `${datePart}T${pad(dto.time.h || 0, 2)}:${pad(dto.time.m || 0, 2)}:${pad(dto.time.s || 0, 2)}.${pad(dto.time.ms || 0, 3)}` let newDate = new Date(`${newDateWithoutOffset}${offset}`) const newDateTimezoneOffsetHours = getTimezoneOffsetHours({date: newDate, timezone: dto.timezone}) // Check if timezones of `dto.date` and `newDate` match; if not, use the new timezone to re-create `newDate` newDate = newDateTimezoneOffsetHours === offset ? newDate : new Date(`${newDateWithoutOffset}${newDateTimezoneOffsetHours}`) if (dto.time.h !== +new Intl.DateTimeFormat('en-GB', {hour: 'numeric', timeZone: dto.timezone}).formatToParts(newDate)?.[0].value) { newDate = new Date('') } return newDate } const timezoneIana = 'Europe/Bratislava' const tests = [ { expString: '30/10/2022, 01:55:00 GMT+02:00', now: new Date('2022-10-29T23:56:12.006Z'), testName: '[DST to ST] `now` in DST before double hour, `newDate` in DST before double hour', time: {h: 1, m: 55} }, { expString: '30/10/2022, 02:55:00 GMT+02:00', now: new Date('2022-10-29T23:56:12.006Z'), testName: '[DST to ST] `now` in DST before double hour, `newDate` in DST during double hour', time: {h: 2, m: 55} }, // FIXME { expString: '30/10/2022, 02:55:00 GMT+01:00', now: new Date('2022-10-29T23:56:12.006Z'), testName: '[DST to ST] `now` in DST before double hour, `newDate` in ST during double hour', time: {h: 2, m: 55} }, { expString: '30/10/2022, 03:55:00 GMT+01:00', now: new Date('2022-10-29T23:56:12.006Z'), testName: '[DST to ST] `now` in DST before double hour, `newDate` in ST after double hour', time: {h: 3, m: 55} }, { expString: '30/10/2022, 01:55:00 GMT+02:00', now: new Date('2022-10-30T00:56:12.006Z'), testName: '[DST to ST] `now` in DST during double hour, `newDate` in DST before double hour', time: {h: 1, m: 55} }, { expString: '30/10/2022, 02:55:00 GMT+02:00', now: new Date('2022-10-30T00:56:12.006Z'), testName: '[DST to ST] `now` in DST during double hour, `newDate` in DST during double hour', time: {h: 2, m: 55} }, // FIXME { expString: '30/10/2022, 02:55:00 GMT+01:00', now: new Date('2022-10-30T00:56:12.006Z'), testName: '[DST to ST] `now` in DST during double hour, `newDate` in ST during double hour', time: {h: 2, m: 55} }, { expString: '30/10/2022, 03:55:00 GMT+01:00', now: new Date('2022-10-30T00:56:12.006Z'), testName: '[DST to ST] `now` in DST during double hour, `newDate` in ST after double hour', time: {h: 3, m: 55} }, { expString: '30/10/2022, 01:55:00 GMT+02:00', now: new Date('2022-10-30T01:56:12.006Z'), testName: '[DST to ST] `now` in ST during double hour, `newDate` in DST before double hour', time: {h: 1, m: 55} }, // FIXME { expString: '30/10/2022, 02:55:00 GMT+02:00', now: new Date('2022-10-30T01:56:12.006Z'), testName: '[DST to ST] `now` in ST during double hour, `newDate` in DST during double hour', time: {h: 2, m: 55} }, { expString: '30/10/2022, 02:55:00 GMT+01:00', now: new Date('2022-10-30T01:56:12.006Z'), testName: '[DST to ST] `now` in ST during double hour, `newDate` in ST during double hour', time: {h: 2, m: 55} }, { expString: '30/10/2022, 03:55:00 GMT+01:00', now: new Date('2022-10-30T01:56:12.006Z'), testName: '[DST to ST] `now` in ST during double hour, `newDate` in ST after double hour', time: {h: 3, m: 55} }, { expString: '30/10/2022, 01:55:00 GMT+02:00', now: new Date('2022-10-30T02:56:12.006Z'), testName: '[DST to ST] `now` in ST after double hour, `newDate` in DST before double hour', time: {h: 1, m: 55} }, // FIXME { expString: '30/10/2022, 02:55:00 GMT+02:00', now: new Date('2022-10-30T02:56:12.006Z'), testName: '[DST to ST] `now` in ST after double hour, `newDate` in DST during double hour', time: {h: 2, m: 55} }, { expString: '30/10/2022, 02:55:00 GMT+01:00', now: new Date('2022-10-30T02:56:12.006Z'), testName: '[DST to ST] `now` in ST after double hour, `newDate` in ST during double hour', time: {h: 2, m: 55} }, { expString: '30/10/2022, 03:55:00 GMT+01:00', now: new Date('2022-10-30T02:56:12.006Z'), testName: '[DST to ST] `now` in ST after double hour, `newDate` in ST after double hour', time: {h: 3, m: 55} }, { expString: '26/03/2023, 01:55:00 GMT+01:00', now: new Date('2023-03-26T00:56:12.006Z'), testName: '[ST to DST] `now` in ST before skipped hour, `newDate` in ST before skipped hour', time: {h: 1, m: 55} }, // FIXME { expString: 'Invalid Date', now: new Date('2023-03-26T00:56:12.006Z'), testName: '[ST to DST] `now` in ST before skipped hour, `newDate` in ST in skipped hour', time: {h: 2, m: 55} }, { expString: '26/03/2023, 03:55:00 GMT+02:00', now: new Date('2023-03-26T00:56:12.006Z'), testName: '[ST to DST] `now` in ST before skipped hour, `newDate` in DST after skipped hour', time: {h: 3, m: 55} }, { expString: '26/03/2023, 01:55:00 GMT+01:00', now: new Date('2023-03-26T01:56:12.006Z'), testName: '[ST to DST] `now` in DST after skipped hour, `newDate` in ST before skipped hour', time: {h: 1, m: 55} }, // FIXME { expString: 'Invalid Date', now: new Date('2023-03-26T01:56:12.006Z'), testName: '[ST to DST] `now` in DST after skipped hour, `newDate` in ST in skipped hour', time: {h: 2, m: 55} }, { expString: '26/03/2023, 03:55:00 GMT+02:00', now: new Date('2023-03-26T01:56:12.006Z'), testName: '[ST to DST] `now` in DST after skipped hour, `newDate` in DST after skipped hour', time: {h: 3, m: 55} } // TODO: Add a test of a date in DST and ST on a day on which there is no timezone change (two tests in total, one for DST and another for ST). ] const results = tests.map(t => { const newDate = setLocalTime({date: t.now, time: t.time, timezone: timezoneIana}) const newDateString = newDate.toLocaleString('en-GB', {timeZone: timezoneIana, timeZoneName: 'longOffset'}) const testResult = newDateString === t.expString if (testResult) { console.log(testResult, `: ${t.testName} : ${newDateString}`) } else { console.log(testResult, `: ${t.testName} : ${newDateString} :`, {newDate, newDateString, test: t}) } return testResult }).reduce((a, c, i) => { if (c) { a.passed++ } else { a.failed++ a.failedTestIds.push(i) } return a }, {failed: 0, failedTestIds: [], passed: 0}) console.log(results)

javascript datetime timezone
3个回答
1
投票

它没有解决初始日期和结果跨越偏移量(可能是 DST)的问题,只是代码少了一点。你真的应该使用一个合适的库。

例如

function setLocalTime( date = new Date(), time = {h: 0, m: 0, s: 0, ms: 0}, tz = 'Europe/Bratislava') { let {h, m, s, ms} = time; let z = (n,len) => ('00'+n).slice(-len); let [datePart, offset] = date.toLocaleDateString('sv', { timeZone:tz, timeZoneName:'longOffset' }).split(' GMT'); let timestamp = `${datePart}T` + `${z(h||0,2)}:${z(m||0,2)}:${z(s||0,2)}.${z(ms||0,3)}` + `${offset.replace(String.fromCharCode(8722),'-')}`; return new Date(timestamp); } let tz, d; tz = 'Europe/Bratislava'; d = setLocalTime(new Date(), {h: 15, m: 30, s: 0, ms: 0}, tz); console.log('UTC: ' + d.toISOString()); console.log(tz + ': ' + d.toLocaleString('en-gb',{timeZone: tz, timeZoneName: 'long'})); tz = 'America/New_York'; d = setLocalTime(new Date(), {h: 15, m: 30, s: 0, ms: 0}, tz); console.log('UTC: '+ d.toISOString()); console.log(tz + ': ' + d.toLocaleString('en-gb',{timeZone: tz, timeZoneName: 'long'}));

在 Safari 中,负偏移量中的“−”字符(字符代码 8722)无法正确解析,因此将其替换为连字符。此外,

timeZoneName:'longOffset'

可能还没有得到广泛支持。

    


0
投票
Date

对象通常期望本地(浏览器)时间中的时间定义并将其存储为 UTC 时间。您可以显式设置 使用

.setUTC<time part>()
方法获取 UTC 时区的时间。您可以使用参数为
hours
.setUTCHours()
函数设置时区 GMT+2 的时间
hours-2

const d=new Date(),hours=10,minutes=40; d.setUTCHours(hours-2);d.setUTCMinutes(minutes); console.log("GMT/UTC:",d); // UTC time ("Z") console.log("New York:",d.toLocaleString("en-US",{timeZone:"America/New_York"})); // local time US console.log("Berlin:",d.toLocaleString("de-DE",{timeZone:"Europe/Berlin"})); // local time Germany (GMT+2)

方法

.setUTCMinutes()

setMinutes()
在大多数情况下会达到相同的结果。一个值得注意的例外是时区“亚洲/加尔各答”,它将应用 30 分钟的偏移。
    


0
投票
Date

对象并且您想要更改其时间(但不是特定时区的日期,无论该时间的 UTC 日期如何) ,您可以为该函数提供该

Date
对象、所需时间、时区以及您是否喜欢使用新时区(可选)(见下文)。
我必须添加 

preferNewTimezone

参数,因为所谓的

双小时
(非 UTC 时区中的小时,由于将时钟调慢一小时而出现两次),因为它们无法输出日期(包括时区)偏移)我预料到了。 我并不是说它很快也不完美,但是它确实有效。 :)

我在

Europe/Bratislava

时区创建了 52 个此函数的测试。他们都通过了。我认为它适用于任何时区。如果没有,并且您发现问题或有改进/优化,我想听听。

/** * Set time provided in a timezone * * @param {Date} [dto.date = new Date()] Date object to work with * @param {boolean} [dto.preferNewTimezone = false] Whether to prefer new timezone for double hours * @param {number} [dto.time.h = 0] Hour to set * @param {number} [dto.time.m = 0] Minute to set * @param {number} [dto.time.s = 0] Second to set * @param {number} [dto.time.ms = 0] Millisecond to set * @param {string} [dto.timezone = 'Europe/Bratislava'] Timezone of `dto.time` * * @return {Date} Date object */ function setLocalTime(dto = { date: new Date(), preferNewTimezone: false, time: {h: 0, m: 0, ms: 0, s: 0}, timezone: 'Europe/Bratislava' }) { const defaultTime = {h: 0, m: 0, ms: 0, s: 0} const defaultTimeKeys = Object.keys(defaultTime) // src: https://stackoverflow.com/a/44118363/3408342 if (!Intl || !Intl.DateTimeFormat().resolvedOptions().timeZone) { throw new Error('`Intl` API is not available or it does not contain a list of timezone identifiers in this environment') } if (!(dto.date instanceof Date)) { throw Error('`date` must be a `Date` object.') } try { Intl.DateTimeFormat(undefined, {timeZone: dto.timezone}) } catch (e) { throw Error('`timezone` must be a valid IANA timezone.') } if ( typeof dto.time !== 'undefined' && typeof dto.time !== 'object' && dto.time instanceof Object && Object.keys(dto.time).every(v => defaultTimeKeys.includes(v)) ) { throw Error('`time` must be an object of `{h: number, m: number, s: number, ms: number}` format, where numbers should be valid time values.') } dto.time = Object.assign({}, defaultTime, dto.time) /** * Whether a date falls in double hour in a particular timezone * * @param {Date} dto.date Date * @param {string} dto.timezone IANA timezone * @return {boolean} `true` if the specified Date falls in double hour in a particular timezone, `false` otherwise */ const isInDoubleHour = (dto = {date: new Date(), timezone: 'Europe/Bratislava'}) => { // Get hour in `dto.timezone` of timezones an hour before and after `dto.date` const hourBeforeHour = +new Intl.DateTimeFormat('en-GB', {hour: 'numeric', timeZone: dto.timezone}).formatToParts(new Date(new Date(dto.date).setUTCHours(dto.date.getUTCHours() - 1)))?.[0].value const hourDateHour = +new Intl.DateTimeFormat('en-GB', {hour: 'numeric', timeZone: dto.timezone}).formatToParts(dto.date)?.[0].value const hourAfterHour = +new Intl.DateTimeFormat('en-GB', {hour: 'numeric', timeZone: dto.timezone}).formatToParts(new Date(new Date(dto.date).setUTCHours(dto.date.getUTCHours() + 1)))?.[0].value return hourBeforeHour === hourDateHour || hourAfterHour === hourDateHour } const getTimezoneOffsetHours = ({date, localisedDate, returnNumber, timezone}) => { let offsetString if (localisedDate) { offsetString = localisedDate.find(i => i.type === 'timeZoneName').value.match(/[\d+:-]+$/)?.[0] } else { offsetString = new Intl .DateTimeFormat('en-GB', {timeZone: timezone, timeZoneName: 'longOffset'}) .formatToParts(date) .find(i => i.type === 'timeZoneName').value.match(/[\d+:-]+$/)?.[0] } return returnNumber ? offsetString.split(':').reduce((a, c) => /^[+-]/.test(c) ? +c * 60 : a + +c, 0) : offsetString } /** * Pad a number with zeros from left to a required length * * @param {number} n Number * @param {number} len Length * @return {string} Padded number */ const pad = (n, len) => `00${n}`.slice(-len) let [datePart, offset] = dto.date.toLocaleDateString('sv', { timeZone: dto.timezone, timeZoneName: 'longOffset' }).split(/ GMT|\//) offset = offset.replace(String.fromCharCode(8722), '-') const newDateWithoutOffset = `${datePart}T${pad(dto.time.h || 0, 2)}:${pad(dto.time.m || 0, 2)}:${pad(dto.time.s || 0, 2)}.${pad(dto.time.ms || 0, 3)}` let newDate = new Date(`${newDateWithoutOffset}${offset}`) const newDateTimezoneOffsetHours = getTimezoneOffsetHours({date: newDate, timezone: dto.timezone}) // Check if timezones of `dto.date` and `newDate` match; if not, use the new timezone to re-create `newDate` newDate = newDateTimezoneOffsetHours === offset ? newDate : new Date(`${newDateWithoutOffset}${newDateTimezoneOffsetHours}`) // Invalidate the date in `newDate` when the hour defined by user is not the same as the hour of `newDate` formatted in the user-defined timezone if (dto.time.h !== +new Intl.DateTimeFormat('en-GB', {hour: 'numeric', timeZone: dto.timezone}).formatToParts(newDate)?.[0].value) { newDate = new Date('') } // Check if the user prefers using the new timezone when `newDate` is in double hour newDate = dto.preferNewTimezone && !isNaN(newDate) && isInDoubleHour({date: newDate, timezone: dto.timezone}) ? new Date(`${newDateWithoutOffset}${getTimezoneOffsetHours({date: new Date(new Date(newDate).setUTCHours(dto.date.getUTCHours() + 1)), timezone: dto.timezone})}`) : newDate return newDate } const timezoneIana = 'Europe/Bratislava' const tests = [ { expString: '30/10/2022, 01:55:00 GMT+02:00', now: new Date('2022-10-29T23:56:12.006Z'), preferNewTimezone: false, testName: '[DST to ST] `now` in DST before double hour, `newDate` in DST before double hour [don\'t prefer new timezone]', time: {h: 1, m: 55} }, { expString: '30/10/2022, 02:55:00 GMT+02:00', now: new Date('2022-10-29T23:56:12.006Z'), preferNewTimezone: false, testName: '[DST to ST] `now` in DST before double hour, `newDate` in DST during double hour [don\'t prefer new timezone]', time: {h: 2, m: 55} }, { expString: '30/10/2022, 02:55:00 GMT+02:00', now: new Date('2022-10-29T23:56:12.006Z'), preferNewTimezone: false, testName: '[DST to ST] `now` in DST before double hour, `newDate` in DST during double hour [don\'t prefer new timezone]', time: {h: 2, m: 55} }, { expString: '30/10/2022, 03:55:00 GMT+01:00', now: new Date('2022-10-29T23:56:12.006Z'), preferNewTimezone: false, testName: '[DST to ST] `now` in DST before double hour, `newDate` in ST after double hour [don\'t prefer new timezone]', time: {h: 3, m: 55} }, { expString: '30/10/2022, 01:55:00 GMT+02:00', now: new Date('2022-10-30T00:56:12.006Z'), preferNewTimezone: false, testName: '[DST to ST] `now` in DST during double hour, `newDate` in DST before double hour [don\'t prefer new timezone]', time: {h: 1, m: 55} }, { expString: '30/10/2022, 02:55:00 GMT+02:00', now: new Date('2022-10-30T00:56:12.006Z'), preferNewTimezone: false, testName: '[DST to ST] `now` in DST during double hour, `newDate` in DST during double hour [don\'t prefer new timezone]', time: {h: 2, m: 55} }, { expString: '30/10/2022, 02:55:00 GMT+02:00', now: new Date('2022-10-30T00:56:12.006Z'), preferNewTimezone: false, testName: '[DST to ST] `now` in DST during double hour, `newDate` in DST during double hour [don\'t prefer new timezone]', time: {h: 2, m: 55} }, { expString: '30/10/2022, 03:55:00 GMT+01:00', now: new Date('2022-10-30T00:56:12.006Z'), preferNewTimezone: false, testName: '[DST to ST] `now` in DST during double hour, `newDate` in ST after double hour [don\'t prefer new timezone]', time: {h: 3, m: 55} }, { expString: '30/10/2022, 01:55:00 GMT+02:00', now: new Date('2022-10-30T01:56:12.006Z'), preferNewTimezone: false, testName: '[DST to ST] `now` in ST during double hour, `newDate` in DST before double hour [don\'t prefer new timezone]', time: {h: 1, m: 55} }, { expString: '30/10/2022, 02:55:00 GMT+01:00', now: new Date('2022-10-30T01:56:12.006Z'), preferNewTimezone: false, testName: '[DST to ST] `now` in ST during double hour, `newDate` in ST during double hour [don\'t prefer new timezone]', time: {h: 2, m: 55} }, { expString: '30/10/2022, 02:55:00 GMT+01:00', now: new Date('2022-10-30T01:56:12.006Z'), preferNewTimezone: false, testName: '[DST to ST] `now` in ST during double hour, `newDate` in ST during double hour [don\'t prefer new timezone]', time: {h: 2, m: 55} }, { expString: '30/10/2022, 03:55:00 GMT+01:00', now: new Date('2022-10-30T01:56:12.006Z'), preferNewTimezone: false, testName: '[DST to ST] `now` in ST during double hour, `newDate` in ST after double hour [don\'t prefer new timezone]', time: {h: 3, m: 55} }, { expString: '30/10/2022, 01:55:00 GMT+02:00', now: new Date('2022-10-30T02:56:12.006Z'), preferNewTimezone: false, testName: '[DST to ST] `now` in ST after double hour, `newDate` in DST before double hour [don\'t prefer new timezone]', time: {h: 1, m: 55} }, { expString: '30/10/2022, 02:55:00 GMT+01:00', now: new Date('2022-10-30T02:56:12.006Z'), preferNewTimezone: false, testName: '[DST to ST] `now` in ST after double hour, `newDate` in ST during double hour [don\'t prefer new timezone]', time: {h: 2, m: 55} }, { expString: '30/10/2022, 02:55:00 GMT+01:00', now: new Date('2022-10-30T02:56:12.006Z'), preferNewTimezone: false, testName: '[DST to ST] `now` in ST after double hour, `newDate` in ST during double hour [don\'t prefer new timezone]', time: {h: 2, m: 55} }, { expString: '30/10/2022, 03:55:00 GMT+01:00', now: new Date('2022-10-30T02:56:12.006Z'), preferNewTimezone: false, testName: '[DST to ST] `now` in ST after double hour, `newDate` in ST after double hour [don\'t prefer new timezone]', time: {h: 3, m: 55} }, { expString: '26/03/2023, 01:55:00 GMT+01:00', now: new Date('2023-03-26T00:56:12.006Z'), preferNewTimezone: false, testName: '[ST to DST] `now` in ST before skipped hour, `newDate` in ST before skipped hour [don\'t prefer new timezone]', time: {h: 1, m: 55} }, { expString: 'Invalid Date', now: new Date('2023-03-26T00:56:12.006Z'), preferNewTimezone: false, testName: '[ST to DST] `now` in ST before skipped hour, `newDate` in ST in skipped hour [don\'t prefer new timezone]', time: {h: 2, m: 55} }, { expString: '26/03/2023, 03:55:00 GMT+02:00', now: new Date('2023-03-26T00:56:12.006Z'), preferNewTimezone: false, testName: '[ST to DST] `now` in ST before skipped hour, `newDate` in DST after skipped hour [don\'t prefer new timezone]', time: {h: 3, m: 55} }, { expString: '26/03/2023, 01:55:00 GMT+01:00', now: new Date('2023-03-26T01:56:12.006Z'), preferNewTimezone: false, testName: '[ST to DST] `now` in DST after skipped hour, `newDate` in ST before skipped hour [don\'t prefer new timezone]', time: {h: 1, m: 55} }, { expString: 'Invalid Date', now: new Date('2023-03-26T01:56:12.006Z'), preferNewTimezone: false, testName: '[ST to DST] `now` in DST after skipped hour, `newDate` in ST in skipped hour [don\'t prefer new timezone]', time: {h: 2, m: 55} }, { expString: '26/03/2023, 03:55:00 GMT+02:00', now: new Date('2023-03-26T01:56:12.006Z'), preferNewTimezone: false, testName: '[ST to DST] `now` in DST after skipped hour, `newDate` in DST after skipped hour [don\'t prefer new timezone]', time: {h: 3, m: 55} }, { expString: '30/10/2022, 01:55:00 GMT+02:00', now: new Date('2022-10-29T23:56:12.006Z'), preferNewTimezone: true, testName: '[DST to ST] `now` in DST before double hour, `newDate` in DST before double hour [prefer new timezone] ', time: {h: 1, m: 55} }, { expString: '30/10/2022, 02:55:00 GMT+01:00', now: new Date('2022-10-29T23:56:12.006Z'), preferNewTimezone: true, testName: '[DST to ST] `now` in DST before double hour, `newDate` in ST during double hour [prefer new timezone] ', time: {h: 2, m: 55} }, { expString: '30/10/2022, 02:55:00 GMT+01:00', now: new Date('2022-10-29T23:56:12.006Z'), preferNewTimezone: true, testName: '[DST to ST] `now` in DST before double hour, `newDate` in ST during double hour [prefer new timezone] ', time: {h: 2, m: 55} }, { expString: '30/10/2022, 03:55:00 GMT+01:00', now: new Date('2022-10-29T23:56:12.006Z'), preferNewTimezone: true, testName: '[DST to ST] `now` in DST before double hour, `newDate` in ST after double hour [prefer new timezone] ', time: {h: 3, m: 55} }, { expString: '30/10/2022, 01:55:00 GMT+02:00', now: new Date('2022-10-30T00:56:12.006Z'), preferNewTimezone: true, testName: '[DST to ST] `now` in DST during double hour, `newDate` in DST before double hour [prefer new timezone] ', time: {h: 1, m: 55} }, { expString: '30/10/2022, 02:55:00 GMT+01:00', now: new Date('2022-10-30T00:56:12.006Z'), preferNewTimezone: true, testName: '[DST to ST] `now` in DST during double hour, `newDate` in ST during double hour [prefer new timezone] ', time: {h: 2, m: 55} }, { expString: '30/10/2022, 02:55:00 GMT+01:00', now: new Date('2022-10-30T00:56:12.006Z'), preferNewTimezone: true, testName: '[DST to ST] `now` in DST during double hour, `newDate` in ST during double hour [prefer new timezone] ', time: {h: 2, m: 55} }, { expString: '30/10/2022, 03:55:00 GMT+01:00', now: new Date('2022-10-30T00:56:12.006Z'), preferNewTimezone: true, testName: '[DST to ST] `now` in DST during double hour, `newDate` in ST after double hour [prefer new timezone] ', time: {h: 3, m: 55} }, { expString: '30/10/2022, 01:55:00 GMT+02:00', now: new Date('2022-10-30T01:56:12.006Z'), preferNewTimezone: true, testName: '[DST to ST] `now` in ST during double hour, `newDate` in DST before double hour [prefer new timezone] ', time: {h: 1, m: 55} }, { expString: '30/10/2022, 02:55:00 GMT+01:00', now: new Date('2022-10-30T01:56:12.006Z'), preferNewTimezone: true, testName: '[DST to ST] `now` in ST during double hour, `newDate` in ST during double hour [prefer new timezone] ', time: {h: 2, m: 55} }, { expString: '30/10/2022, 02:55:00 GMT+01:00', now: new Date('2022-10-30T01:56:12.006Z'), preferNewTimezone: true, testName: '[DST to ST] `now` in ST during double hour, `newDate` in ST during double hour [prefer new timezone] ', time: {h: 2, m: 55} }, { expString: '30/10/2022, 03:55:00 GMT+01:00', now: new Date('2022-10-30T01:56:12.006Z'), preferNewTimezone: true, testName: '[DST to ST] `now` in ST during double hour, `newDate` in ST after double hour [prefer new timezone] ', time: {h: 3, m: 55} }, { expString: '30/10/2022, 01:55:00 GMT+02:00', now: new Date('2022-10-30T02:56:12.006Z'), preferNewTimezone: true, testName: '[DST to ST] `now` in ST after double hour, `newDate` in DST before double hour [prefer new timezone] ', time: {h: 1, m: 55} }, { expString: '30/10/2022, 02:55:00 GMT+01:00', now: new Date('2022-10-30T02:56:12.006Z'), preferNewTimezone: true, testName: '[DST to ST] `now` in ST after double hour, `newDate` in ST during double hour [prefer new timezone] ', time: {h: 2, m: 55} }, { expString: '30/10/2022, 02:55:00 GMT+01:00', now: new Date('2022-10-30T02:56:12.006Z'), preferNewTimezone: true, testName: '[DST to ST] `now` in ST after double hour, `newDate` in ST during double hour [prefer new timezone] ', time: {h: 2, m: 55} }, { expString: '30/10/2022, 03:55:00 GMT+01:00', now: new Date('2022-10-30T02:56:12.006Z'), preferNewTimezone: true, testName: '[DST to ST] `now` in ST after double hour, `newDate` in ST after double hour [prefer new timezone] ', time: {h: 3, m: 55} }, { expString: '26/03/2023, 01:55:00 GMT+01:00', now: new Date('2023-03-26T00:56:12.006Z'), preferNewTimezone: true, testName: '[ST to DST] `now` in ST before skipped hour, `newDate` in ST before skipped hour [prefer new timezone] ', time: {h: 1, m: 55} }, { expString: 'Invalid Date', now: new Date('2023-03-26T00:56:12.006Z'), preferNewTimezone: true, testName: '[ST to DST] `now` in ST before skipped hour, `newDate` in ST in skipped hour [prefer new timezone] ', time: {h: 2, m: 55} }, { expString: '26/03/2023, 03:55:00 GMT+02:00', now: new Date('2023-03-26T00:56:12.006Z'), preferNewTimezone: true, testName: '[ST to DST] `now` in ST before skipped hour, `newDate` in DST after skipped hour [prefer new timezone] ', time: {h: 3, m: 55} }, { expString: '26/03/2023, 01:55:00 GMT+01:00', now: new Date('2023-03-26T01:56:12.006Z'), preferNewTimezone: true, testName: '[ST to DST] `now` in DST after skipped hour, `newDate` in ST before skipped hour [prefer new timezone] ', time: {h: 1, m: 55} }, { expString: 'Invalid Date', now: new Date('2023-03-26T01:56:12.006Z'), preferNewTimezone: true, testName: '[ST to DST] `now` in DST after skipped hour, `newDate` in ST in skipped hour [prefer new timezone] ', time: {h: 2, m: 55} }, { expString: '26/03/2023, 03:55:00 GMT+02:00', now: new Date('2023-03-26T01:56:12.006Z'), preferNewTimezone: true, testName: '[ST to DST] `now` in DST after skipped hour, `newDate` in DST after skipped hour [prefer new timezone] ', time: {h: 3, m: 55} }, { expString: '01/01/2023, 03:55:00 GMT+01:00', now: new Date('2023-01-01T10:00:00.000Z'), preferNewTimezone: true, testName: '[ST] `now` in ST, `newDate` in ST before `now` [prefer new timezone] ', time: {h: 3, m: 55} }, { expString: '01/01/2023, 12:00:00 GMT+01:00', now: new Date('2023-01-01T10:00:00.000Z'), preferNewTimezone: true, testName: '[ST] `now` in ST, `newDate` in ST after `now` [prefer new timezone] ', time: {h: 12} }, { expString: '01/07/2023, 03:55:00 GMT+02:00', now: new Date('2023-07-01T10:00:00.000Z'), preferNewTimezone: true, testName: '[ST] `now` in DST, `newDate` in DST before `now` [prefer new timezone] ', time: {h: 3, m: 55} }, { expString: '01/07/2023, 12:00:00 GMT+02:00', now: new Date('2023-07-01T10:00:00.000Z'), preferNewTimezone: true, testName: '[ST] `now` in DST, `newDate` in DST after `now` [prefer new timezone] ', time: {h: 12} }, { expString: '01/01/2023, 03:55:00 GMT+01:00', now: new Date('2023-01-01T10:00:00.000Z'), preferNewTimezone: false, testName: '[ST] `now` in ST, `newDate` in ST before `now` [don\'t prefer new timezone]', time: {h: 3, m: 55} }, { expString: '01/01/2023, 12:00:00 GMT+01:00', now: new Date('2023-01-01T10:00:00.000Z'), preferNewTimezone: false, testName: '[ST] `now` in ST, `newDate` in ST after `now` [don\'t prefer new timezone]', time: {h: 12} }, { expString: '01/07/2023, 03:55:00 GMT+02:00', now: new Date('2023-07-01T10:00:00.000Z'), preferNewTimezone: false, testName: '[ST] `now` in DST, `newDate` in DST before `now` [don\'t prefer new timezone]', time: {h: 3, m: 55} }, { expString: '01/07/2023, 12:00:00 GMT+02:00', now: new Date('2023-07-01T10:00:00.000Z'), preferNewTimezone: false, testName: '[ST] `now` in DST, `newDate` in DST after `now` [don\'t prefer new timezone]', time: {h: 12} } ] const results = tests.map(t => { const newDate = setLocalTime({date: t.now, preferNewTimezone: t.preferNewTimezone, time: t.time, timezone: timezoneIana}) const newDateString = newDate.toLocaleString('en-GB', {timeZone: timezoneIana, timeZoneName: 'longOffset'}) const testResult = newDateString === t.expString if (testResult) { console.log(testResult, `: ${t.testName} : ${newDateString}`) } else { console.log(testResult, `: ${t.testName} : ${newDateString} :`, {newDate, newDateString, test: t}) } return testResult }).reduce((a, c, i) => { if (c) { a.passed++ } else { a.failed++ a.failedTestIds.push(i) } return a }, {failed: 0, failedTestIds: [], passed: 0}) console.log(results)

© www.soinside.com 2019 - 2024. All rights reserved.