Repository: moment/luxon
Pull request #1668 (2024-11-21 10:24:14)

add lowercase t and z to ISO parsing regexes and unit tests
I've added the unit tests requested in the discussion on benjamin-pike's [PR #1624](https://github.com/moment/luxon/pull/1624)

Adds the ability for DateTime.fromISO to parse ISO strings containing lowercase t and z characters.
Resolves https://github.com/moment/luxon/issues/1610

dobon: @diesieben07 Hey, sorry if this is not the right way to request review, and please let me know if there's a more appropriate/official way, but can you or another maintainer take a look at this PR? I see you've been active most recently.

I've also got another unrelated PR ready for review that I'd appreciate feedback on: https://github.com/moment/luxon/pull/1670

Both of these PRs are fixes for other people's PRs that were tagged with "needs work".

Patch:
diff --git a/src/impl/regexParser.js b/src/impl/regexParser.js
index ab095864..6710d64e 100644
--- a/src/impl/regexParser.js
+++ b/src/impl/regexParser.js
@@ -67,11 +67,11 @@ function simpleParse(...keys) {
 }
 
 // ISO and SQL parsing
-const offsetRegex = /(?:(Z)|([+-]\d\d)(?::?(\d\d))?)/;
+const offsetRegex = /(?:([Zz])|([+-]\d\d)(?::?(\d\d))?)/;
 const isoExtendedZone = `(?:${offsetRegex.source}?(?:\\[(${ianaRegex.source})\\])?)?`;
 const isoTimeBaseRegex = /(\d\d)(?::?(\d\d)(?::?(\d\d)(?:[.,](\d{1,30}))?)?)?/;
 const isoTimeRegex = RegExp(`${isoTimeBaseRegex.source}${isoExtendedZone}`);
-const isoTimeExtensionRegex = RegExp(`(?:T${isoTimeRegex.source})?`);
+const isoTimeExtensionRegex = RegExp(`(?:[Tt]${isoTimeRegex.source})?`);
 const isoYmdRegex = /([+-]\d{6}|\d{4})(?:-?(\d\d)(?:-?(\d\d))?)?/;
 const isoWeekRegex = /(\d{4})-?W(\d\d)(?:-?(\d))?/;
 const isoOrdinalRegex = /(\d{4})-?(\d{3})/;


Test patch:
diff --git a/test/datetime/regexParse.test.js b/test/datetime/regexParse.test.js
index db84b968..85d12002 100644
--- a/test/datetime/regexParse.test.js
+++ b/test/datetime/regexParse.test.js
@@ -72,6 +72,20 @@ test("DateTime.fromISO() optionally adopts the UTC offset provided", () => {
     millisecond: 0,
   });
 
+  // #1610 - lowercase z
+  dt = DateTime.fromISO("1983-10-14T13:30z", { setZone: true });
+  expect(dt.zone.name).toBe("UTC");
+  expect(dt.offset).toBe(0);
+  expect(dt.toObject()).toEqual({
+    year: 1983,
+    month: 10,
+    day: 14,
+    hour: 13,
+    minute: 30,
+    second: 0,
+    millisecond: 0,
+  });
+
   // #580
   dt = DateTime.fromISO("2016-05-25T09:08:34.123-00:30", { setZone: true });
   expect(dt.zone.name).toBe("UTC-0:30");
@@ -114,6 +128,18 @@ test("DateTime.fromISO() can optionally specify a zone", () => {
 
 const isSame = (s, expected) => expect(DateTime.fromISO(s).toObject()).toEqual(expected);
 
+test("DateTime.fromISO() accepts both capital T and lowercase t", () => {
+  // #1610
+  const dt = DateTime.fromISO("2016-05-25T09:08:34.123+06:00");
+  isSame("2016-05-25t09:08:34.123+06:00", dt.toObject());
+});
+
+test("DateTime.fromISO() accepts both capital Z and lowercase z", () => {
+  // #1610
+  const dt = DateTime.fromISO("2016-05-25T09:08:34.123Z");
+  isSame("2016-05-25T09:08:34.123z", dt.toObject());
+});
+
 test("DateTime.fromISO() accepts just the year", () => {
   isSame("2016", {
     year: 2016,