From 21ee27b57503f9d57f228973e1699972484e6089 Mon Sep 17 00:00:00 2001 From: Harttle Date: Mon, 24 Apr 2023 23:34:56 +0800 Subject: [PATCH] fix: timezoneOffset ignored in date when preserveTimezones is enabled, fixes #605 --- src/filters/date.ts | 2 +- src/util/liquid-date.ts | 4 +- src/util/timezone-date.ts | 58 ++++++++++++++++----------- test/integration/filters/date.spec.ts | 8 +++- 4 files changed, 45 insertions(+), 27 deletions(-) diff --git a/src/filters/date.ts b/src/filters/date.ts index 0f73608142..b6ed1b1cf6 100644 --- a/src/filters/date.ts +++ b/src/filters/date.ts @@ -26,7 +26,7 @@ export function date (this: FilterImpl, v: string | Date, format?: string, timez if (!isValidDate(date)) return v if (timezoneOffset !== undefined) { date = new TimezoneDate(date, parseTimezoneOffset(date, timezoneOffset)) - } else if (opts.timezoneOffset !== undefined) { + } else if (!(date instanceof TimezoneDate) && opts.timezoneOffset !== undefined) { date = new TimezoneDate(date, parseTimezoneOffset(date, opts.timezoneOffset)) } return strftime(date, format) diff --git a/src/util/liquid-date.ts b/src/util/liquid-date.ts index fb2c348f6f..2891648b6b 100644 --- a/src/util/liquid-date.ts +++ b/src/util/liquid-date.ts @@ -14,6 +14,6 @@ export interface LiquidDate { getMonth(): number; getFullYear(): number; getTimezoneOffset(): number; - toLocaleTimeString(): string; - toLocaleDateString(): string; + toLocaleTimeString(locale?: string, init?: any): string; + toLocaleDateString(locale?: string, init?: any): string; } diff --git a/src/util/timezone-date.ts b/src/util/timezone-date.ts index 283cbc0778..49427e371d 100644 --- a/src/util/timezone-date.ts +++ b/src/util/timezone-date.ts @@ -15,51 +15,63 @@ const ISO8601_TIMEZONE_PATTERN = /([zZ]|([+-])(\d{2}):(\d{2}))$/ export class TimezoneDate implements LiquidDate { private timezoneOffset: number private date: Date + private displayDate: Date constructor (init: string | number | Date | TimezoneDate, timezoneOffset: number) { - if (init instanceof TimezoneDate) { - this.date = init.date - timezoneOffset = init.timezoneOffset - } else { - const diff = (hostTimezoneOffset - timezoneOffset) * OneMinute - const time = new Date(init).getTime() + diff - this.date = new Date(time) - } + this.date = init instanceof TimezoneDate + ? init.date + : new Date(init) this.timezoneOffset = timezoneOffset + + const diff = (hostTimezoneOffset - this.timezoneOffset) * OneMinute + const time = this.date.getTime() + diff + this.displayDate = new Date(time) } getTime () { - return this.date.getTime() + return this.displayDate.getTime() } getMilliseconds () { - return this.date.getMilliseconds() + return this.displayDate.getMilliseconds() } getSeconds () { - return this.date.getSeconds() + return this.displayDate.getSeconds() } getMinutes () { - return this.date.getMinutes() + return this.displayDate.getMinutes() } getHours () { - return this.date.getHours() + return this.displayDate.getHours() } getDay () { - return this.date.getDay() + return this.displayDate.getDay() } getDate () { - return this.date.getDate() + return this.displayDate.getDate() } getMonth () { - return this.date.getMonth() + return this.displayDate.getMonth() } getFullYear () { - return this.date.getFullYear() + return this.displayDate.getFullYear() + } + toLocaleString (locale?: string, init?: any) { + if (locale === undefined) { + return this.displayDate.toLocaleString(locale) + } + return this.date.toLocaleString(locale, init) } - toLocaleTimeString (locale?: string) { - return this.date.toLocaleTimeString(locale) + toLocaleTimeString (locale?: string, init?: any) { + if (locale === undefined) { + return this.displayDate.toLocaleTimeString(locale) + } + return this.date.toLocaleTimeString(locale, init) } - toLocaleDateString (locale?: string) { - return this.date.toLocaleDateString(locale) + toLocaleDateString (locale?: string, init?: any) { + if (locale === undefined) { + return this.displayDate.toLocaleDateString(locale) + } + return this.date.toLocaleDateString(locale, init) } getTimezoneOffset () { return this.timezoneOffset! @@ -87,8 +99,8 @@ export class TimezoneDate implements LiquidDate { // has a timezone specified if (m && m[2] && m[3] && m[4]) { const [, , sign, hours, minutes] = m - const delta = (sign === '+' ? -1 : 1) * (parseInt(hours, 10) * 60 + parseInt(minutes, 10)) - return new TimezoneDate(+new Date(dateString), delta) + const offset = (sign === '+' ? -1 : 1) * (parseInt(hours, 10) * 60 + parseInt(minutes, 10)) + return new TimezoneDate(+new Date(dateString), offset) } return new Date(dateString) } diff --git a/test/integration/filters/date.spec.ts b/test/integration/filters/date.spec.ts index bc42162557..3416197367 100644 --- a/test/integration/filters/date.spec.ts +++ b/test/integration/filters/date.spec.ts @@ -1,4 +1,5 @@ import { LiquidOptions } from '../../../src/liquid-options' +import { Liquid } from '.././../../src/liquid' import { test } from '../../stub/render' describe('filters/date', function () { @@ -98,10 +99,15 @@ describe('filters/date', function () { const scope = { date: new Date('1990-12-31T23:00:00Z') } return test('{{ date | date: "%z"}}', scope, '-0600', opts) }) - it('should work with `preserveTimezones`', function () { + it('opts.timezoneOffset should work with `preserveTimezones`', function () { const opts: LiquidOptions = { timezoneOffset: 600, preserveTimezones: true } return test('{{ "1990-12-31T23:00:00+02:30" | date: "%Y-%m-%dT%H:%M:%S"}}', '1990-12-31T23:00:00', undefined, opts) }) + it('timezoneOffset should work with `preserveTimezones`', async () => { + const liquid = new Liquid({ preserveTimezones: true }) + const html = liquid.parseAndRenderSync('{{ "1990-12-31T23:00:00Z" | date: "%Y-%m-%dT%H:%M:%S", "Asia/Colombo" }}') + expect(html).toEqual('1991-01-01T04:30:00') + }) }) describe('dateFormat', function () { const optsWithoutDateFormat: LiquidOptions = { timezoneOffset: 360 } // -06:00