From 696d2479ce5295c9ad830ad6ac8cb2253130a8f9 Mon Sep 17 00:00:00 2001 From: Wanasit Tanakitrungruang Date: Mon, 16 Sep 2024 13:31:21 +0900 Subject: [PATCH] Fix: ISO format default to local timezone instead of UTC --- src/common/parsers/ISOFormatParser.ts | 62 +++++++++++++-------------- test/en/en_inter_std.test.ts | 58 +++++++++++++------------ test/system.test.ts | 2 + 3 files changed, 62 insertions(+), 60 deletions(-) diff --git a/src/common/parsers/ISOFormatParser.ts b/src/common/parsers/ISOFormatParser.ts index 9f2e1a28..e1ef0dcd 100644 --- a/src/common/parsers/ISOFormatParser.ts +++ b/src/common/parsers/ISOFormatParser.ts @@ -18,7 +18,7 @@ const PATTERN = new RegExp( "(?:" + ":([0-9]{1,2})(?:\\.(\\d{1,4}))?" + ")?" + // :ss.s - "(?:" + + "(" + "Z|([+-]\\d{2}):?(\\d{2})?" + ")?" + // TZD (Z or ±hh:mm or ±hhmm or ±hh) ")?" + @@ -33,8 +33,9 @@ const HOUR_NUMBER_GROUP = 4; const MINUTE_NUMBER_GROUP = 5; const SECOND_NUMBER_GROUP = 6; const MILLISECOND_NUMBER_GROUP = 7; -const TZD_HOUR_OFFSET_GROUP = 8; -const TZD_MINUTE_OFFSET_GROUP = 9; +const TZD_GROUP = 8; +const TZD_HOUR_OFFSET_GROUP = 9; +const TZD_MINUTE_OFFSET_GROUP = 10; export default class ISOFormatParser extends AbstractParserWithWordBoundaryChecking { innerPattern(): RegExp { @@ -42,44 +43,41 @@ export default class ISOFormatParser extends AbstractParserWithWordBoundaryCheck } innerExtract(context: ParsingContext, match: RegExpMatchArray) { - const components: { [component in Component]?: number } = {}; - components["year"] = parseInt(match[YEAR_NUMBER_GROUP]); - components["month"] = parseInt(match[MONTH_NUMBER_GROUP]); - components["day"] = parseInt(match[DATE_NUMBER_GROUP]); - + const components = context.createParsingComponents({ + "year": parseInt(match[YEAR_NUMBER_GROUP]), + "month": parseInt(match[MONTH_NUMBER_GROUP]), + "day": parseInt(match[DATE_NUMBER_GROUP]), + }); if (match[HOUR_NUMBER_GROUP] != null) { - components["hour"] = parseInt(match[HOUR_NUMBER_GROUP]); - components["minute"] = parseInt(match[MINUTE_NUMBER_GROUP]); + components.assign("hour", parseInt(match[HOUR_NUMBER_GROUP])); + components.assign("minute", parseInt(match[MINUTE_NUMBER_GROUP])); if (match[SECOND_NUMBER_GROUP] != null) { - components["second"] = parseInt(match[SECOND_NUMBER_GROUP]); + components.assign("second", parseInt(match[SECOND_NUMBER_GROUP])); } if (match[MILLISECOND_NUMBER_GROUP] != null) { - components["millisecond"] = parseInt(match[MILLISECOND_NUMBER_GROUP]); + components.assign("millisecond", parseInt(match[MILLISECOND_NUMBER_GROUP])); } - - if (match[TZD_HOUR_OFFSET_GROUP] == null) { - components["timezoneOffset"] = 0; - } else { - const hourOffset = parseInt(match[TZD_HOUR_OFFSET_GROUP]); - - let minuteOffset = 0; - if (match[TZD_MINUTE_OFFSET_GROUP] != null) { - minuteOffset = parseInt(match[TZD_MINUTE_OFFSET_GROUP]); + if (match[TZD_GROUP] != null) { + // The Zulu time zone (Z) is equivalent to UTC + let offset = 0; + if (match[TZD_HOUR_OFFSET_GROUP]) { + const hourOffset = parseInt(match[TZD_HOUR_OFFSET_GROUP]); + let minuteOffset = 0; + if (match[TZD_MINUTE_OFFSET_GROUP] != null) { + minuteOffset = parseInt(match[TZD_MINUTE_OFFSET_GROUP]); + } + offset = hourOffset * 60; + if (offset < 0) { + offset -= minuteOffset; + } else { + offset += minuteOffset; + } } - - let offset = hourOffset * 60; - if (offset < 0) { - offset -= minuteOffset; - } else { - offset += minuteOffset; - } - - components["timezoneOffset"] = offset; + components.assign("timezoneOffset", offset); } } - - return components; + return components.addTag("parser/ISOFormatParser"); } } diff --git a/test/en/en_inter_std.test.ts b/test/en/en_inter_std.test.ts index 5348adec..7200487e 100644 --- a/test/en/en_inter_std.test.ts +++ b/test/en/en_inter_std.test.ts @@ -27,34 +27,6 @@ test("Test - Single Expression", function () { expect(result.start).toBeDate(new Date(784043130000)); }); - testSingleCase(chrono, "1994-11-05T13:15:30", new Date(2012, 7, 8), (result) => { - expect(result.start).not.toBeNull(); - expect(result.start.get("year")).toBe(1994); - expect(result.start.get("month")).toBe(11); - expect(result.start.get("day")).toBe(5); - expect(result.start.get("hour")).toBe(13); - expect(result.start.get("minute")).toBe(15); - expect(result.start.get("second")).toBe(30); - expect(result.start.get("timezoneOffset")).toBe(0); - expect(result.text).toBe("1994-11-05T13:15:30"); - - expect(result.start).toBeDate(new Date(784041330000)); - }); - - testSingleCase(chrono, "2015-07-31T12:00:00", new Date(2012, 7, 8), (result) => { - expect(result.start).not.toBeNull(); - expect(result.start.get("year")).toBe(2015); - expect(result.start.get("month")).toBe(7); - expect(result.start.get("day")).toBe(31); - expect(result.start.get("hour")).toBe(12); - expect(result.start.get("minute")).toBe(0); - expect(result.start.get("second")).toBe(0); - expect(result.start.get("timezoneOffset")).toBe(0); - expect(result.text).toBe("2015-07-31T12:00:00"); - - expect(result.start).toBeDate(new Date(1438344000000)); - }); - testSingleCase(chrono, "1994-11-05T13:15:30Z", new Date(2012, 7, 8), (result) => { expect(result.start).not.toBeNull(); expect(result.start.get("year")).toBe(1994); @@ -114,3 +86,33 @@ test("Test - Single Expression", function () { expect(result.start).toBeDate(new Date(1462661100487)); }); }); + +test("Test - Single Expression with local timezeon", function () { + testSingleCase(chrono, "1994-11-05T13:15:30", new Date(2012, 7, 8), (result) => { + expect(result.text).toBe("1994-11-05T13:15:30"); + expect(result.start.get("year")).toBe(1994); + expect(result.start.get("month")).toBe(11); + expect(result.start.get("day")).toBe(5); + expect(result.start.get("hour")).toBe(13); + expect(result.start.get("minute")).toBe(15); + expect(result.start.get("second")).toBe(30); + expect(result.start.get("millisecond")).toBe(0); + + expect(result.start.isCertain("timezoneOffset")).toBe(false); + expect(result.start).toBeDate(new Date("1994-11-05T13:15:30")); + }); + + testSingleCase(chrono, "2015-07-31T12:00:00", new Date(2012, 7, 8), (result) => { + expect(result.text).toBe("2015-07-31T12:00:00"); + expect(result.start.get("year")).toBe(2015); + expect(result.start.get("month")).toBe(7); + expect(result.start.get("day")).toBe(31); + expect(result.start.get("hour")).toBe(12); + expect(result.start.get("minute")).toBe(0); + expect(result.start.get("second")).toBe(0); + expect(result.start.get("millisecond")).toBe(0); + + expect(result.start.isCertain("timezoneOffset")).toBe(false); + expect(result.start).toBeDate(new Date("2015-07-31T12:00:00")); + }); +}); diff --git a/test/system.test.ts b/test/system.test.ts index 6c16bda6..b33df466 100644 --- a/test/system.test.ts +++ b/test/system.test.ts @@ -241,4 +241,6 @@ test("Test - Compare with native js", () => { testByCompareWithNative("Fri, 31 Mar 2000 07:00:00 UTC"); testByCompareWithNative("2014-12-14T18:22:14.759Z"); + + testByCompareWithNative("2024-01-01T00:00"); });