Repository: moment/luxon (js)

Issue:
DateTime.fromFormat fails in some cases when running Node 18.13.0
**Describe the bug**
I Node 18.13.0 parsing DateTime using the fromFormat method can in some cases fail parsing, where running in previous Node version it would not.

**To Reproduce**

```js
const { DateTime } = require("luxon");

const format = "M/d/yyyy tt";
const dateTimeString = "1/17/2023 11:00:00 PM";

const dateTime = DateTime.fromFormat(dateTimeString, format);

console.log(dateTime.isValid);
// "false" when running in 18.13.0
// "true" when running in 18.12.0

console.log(dateTime.toISO());
// "null" when running in 18.13.0
// "2023-01-17T23:00:00.000+01:00" when running in 18.12.0
```


**Actual vs Expected behavior**
I would expect the outcome of running the snippet to be the same in 18.12.0 and 18.13.0 and that the parsed DateTime is valid.
Instead in 18.12.0 the DateTime is correctly parsed while in 18.13.0 it is invalid.


**Desktop (please complete the following information):**

- OS: Windows 11 (but originally noticed noticed in debian based docker container)
- Browser: Node 18.13.0
- Luxon version: 3.2.1
- Your timezone: Europe/Copenhagen

**Additional context**
Add any other context about the problem here.


Pull request:
Fix support for Node.js 18.13+
Fixes #1364

Patch:
diff --git a/src/impl/formatter.js b/src/impl/formatter.js
index 4dcd6be7..7fe6891f 100644
--- a/src/impl/formatter.js
+++ b/src/impl/formatter.js
@@ -47,6 +47,9 @@ export default class Formatter {
   }
 
   static parseFormat(fmt) {
+    // white-space is always considered a literal in user-provided formats
+    // the " " token has a special meaning (see unitForToken)
+
     let current = null,
       currentFull = "",
       bracketed = false;
@@ -55,7 +58,7 @@ export default class Formatter {
       const c = fmt.charAt(i);
       if (c === "'") {
         if (currentFull.length > 0) {
-          splits.push({ literal: bracketed, val: currentFull });
+          splits.push({ literal: bracketed || /^\s+$/.test(currentFull), val: currentFull });
         }
         current = null;
         currentFull = "";
@@ -66,7 +69,7 @@ export default class Formatter {
         currentFull += c;
       } else {
         if (currentFull.length > 0) {
-          splits.push({ literal: false, val: currentFull });
+          splits.push({ literal: /^\s+$/.test(currentFull), val: currentFull });
         }
         currentFull = c;
         current = c;
@@ -74,7 +77,7 @@ export default class Formatter {
     }
 
     if (currentFull.length > 0) {
-      splits.push({ literal: bracketed, val: currentFull });
+      splits.push({ literal: bracketed || /^\s+$/.test(currentFull), val: currentFull });
     }
 
     return splits;
diff --git a/src/impl/tokenParser.js b/src/impl/tokenParser.js
index b91cdf49..5a913b0f 100644
--- a/src/impl/tokenParser.js
+++ b/src/impl/tokenParser.js
@@ -180,6 +180,10 @@ function unitForToken(token, loc) {
         // because we don't have any way to figure out what they are
         case "z":
           return simple(/[a-z_+-/]{1,256}?/i);
+        // this special-case "token" represents a place where a macro-token expanded into a white-space literal
+        // in this case we accept any non-newline white-space
+        case " ":
+          return simple(/[^\S\n\r]/);
         default:
           return literal(t);
       }
@@ -237,9 +241,10 @@ function tokenForPart(part, formatOpts) {
   const { type, value } = part;
 
   if (type === "literal") {
+    const isSpace = /^\s+$/.test(value);
     return {
-      literal: true,
-      val: value,
+      literal: !isSpace,
+      val: isSpace ? " " : value,
     };
   }
 
diff --git a/src/impl/util.js b/src/impl/util.js
index c07136f6..81bffc6e 100644
--- a/src/impl/util.js
+++ b/src/impl/util.js
@@ -166,7 +166,10 @@ export function objToLocalTS(obj) {
   // for legacy reasons, years between 0 and 99 are interpreted as 19XX; revert that
   if (obj.year < 100 && obj.year >= 0) {
     d = new Date(d);
-    d.setUTCFullYear(d.getUTCFullYear() - 1900);
+    // set the month and day again, this is necessary because year 2000 is a leap year, but year 100 is not
+    // so if obj.year is in 99, but obj.day makes it roll over into year 100,
+    // the calculations done by Date.UTC are using year 2000 - which is incorrect
+    d.setUTCFullYear(obj.year, obj.month - 1, obj.day);
   }
   return +d;
 }


Test patch:
diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
index b533278d..b3d64cca 100644
--- a/.github/workflows/test.yml
+++ b/.github/workflows/test.yml
@@ -18,7 +18,7 @@ jobs:
 
     strategy:
       matrix:
-        node-version: [18.9]
+        node-version: [18.13]
 
     steps:
     - uses: actions/checkout@v2
diff --git a/test/datetime/format.test.js b/test/datetime/format.test.js
index 23dcfd77..355cf222 100644
--- a/test/datetime/format.test.js
+++ b/test/datetime/format.test.js
@@ -376,34 +376,34 @@ test("DateTime#toLocaleString() returns something different for invalid DateTime
 
 test("DateTime#toLocaleString() shows things in the right IANA zone", () => {
   expect(dt.setZone("America/New_York").toLocaleString(DateTime.DATETIME_SHORT)).toBe(
-    "5/25/1982, 5:23 AM"
+    "5/25/1982, 5:23 AM"
   );
 });
 
 test("DateTime#toLocaleString() shows things in the right fixed-offset zone", () => {
-  expect(dt.setZone("UTC-8").toLocaleString(DateTime.DATETIME_SHORT)).toBe("5/25/1982, 1:23 AM");
+  expect(dt.setZone("UTC-8").toLocaleString(DateTime.DATETIME_SHORT)).toBe("5/25/1982, 1:23 AM");
 });
 
 test("DateTime#toLocaleString() shows things in the right fixed-offset zone when showing the zone", () => {
   expect(dt.setZone("UTC-8").toLocaleString(DateTime.DATETIME_FULL)).toBe(
-    "May 25, 1982 at 1:23 AM GMT-8"
+    "May 25, 1982 at 1:23 AM GMT-8"
   );
 });
 
 test("DateTime#toLocaleString() shows things with UTC if fixed-offset zone with 0 offset is used", () => {
   expect(dt.setZone("UTC").toLocaleString(DateTime.DATETIME_FULL)).toBe(
-    "May 25, 1982 at 9:23 AM UTC"
+    "May 25, 1982 at 9:23 AM UTC"
   );
 });
 
 test("DateTime#toLocaleString() does the best it can with unsupported fixed-offset zone when showing the zone", () => {
   expect(dt.setZone("UTC+4:30").toLocaleString(DateTime.DATETIME_FULL)).toBe(
-    "May 25, 1982 at 9:23 AM UTC"
+    "May 25, 1982 at 9:23 AM UTC"
   );
 });
 
 test("DateTime#toLocaleString uses locale-appropriate time formats", () => {
-  expect(dt.reconfigure({ locale: "en-US" }).toLocaleString(DateTime.TIME_SIMPLE)).toBe("9:23 AM");
+  expect(dt.reconfigure({ locale: "en-US" }).toLocaleString(DateTime.TIME_SIMPLE)).toBe("9:23 AM");
   expect(dt.reconfigure({ locale: "en-US" }).toLocaleString(DateTime.TIME_24_SIMPLE)).toBe("09:23");
 
   // France has 24-hour time by default
@@ -429,7 +429,7 @@ test("DateTime#toLocaleString() accepts a zone even when the zone is set", () =>
       timeZoneName: "short",
       timeZone: "America/Los_Angeles",
     })
-  ).toBe("2:23 AM PDT");
+  ).toBe("2:23 AM PDT");
 });
 
 //------
diff --git a/test/datetime/math.test.js b/test/datetime/math.test.js
index 848d5ba6..aab17683 100644
--- a/test/datetime/math.test.js
+++ b/test/datetime/math.test.js
@@ -107,6 +107,13 @@ test("DateTime#plus works across the 100 barrier", () => {
   expect(d.day).toBe(2);
 });
 
+test("DateTime#plus works across the 100 barrier when passing through February", () => {
+  const d = DateTime.fromISO("0099-12-31").plus({ day: 61 });
+  expect(d.year).toBe(100);
+  expect(d.month).toBe(3);
+  expect(d.day).toBe(2);
+});
+
 test("DateTime#plus renders invalid when out of max. datetime range using days", () => {
   const d = DateTime.utc(1970, 1, 1, 0, 0, 0, 0).plus({ day: 1e8 + 1 });
   expect(d.isValid).toBe(false);
diff --git a/test/datetime/toFormat.test.js b/test/datetime/toFormat.test.js
index f8f6dfc7..f73b5aa0 100644
--- a/test/datetime/toFormat.test.js
+++ b/test/datetime/toFormat.test.js
@@ -370,8 +370,8 @@ test("DateTime#toFormat('DDDD') returns a long date representation", () => {
 });
 
 test("DateTime#toFormat('t') returns a short time representation", () => {
-  expect(dt.toFormat("t")).toBe("9:23 AM");
-  expect(dt.set({ hour: 13 }).toFormat("t")).toBe("1:23 PM");
+  expect(dt.toFormat("t")).toBe("9:23 AM");
+  expect(dt.set({ hour: 13 }).toFormat("t")).toBe("1:23 PM");
   expect(dt.reconfigure({ locale: "fr" }).toFormat("t")).toBe("09:23");
   expect(dt.set({ hour: 13 }).reconfigure({ locale: "fr" }).toFormat("t")).toBe("13:23");
 });
@@ -384,8 +384,8 @@ test("DateTime#toFormat('T') returns a short 24-hour time representation", () =>
 });
 
 test("DateTime#toFormat('tt') returns a medium time representation", () => {
-  expect(dt.toFormat("tt")).toBe("9:23:54 AM");
-  expect(dt.set({ hour: 13 }).toFormat("tt")).toBe("1:23:54 PM");
+  expect(dt.toFormat("tt")).toBe("9:23:54 AM");
+  expect(dt.set({ hour: 13 }).toFormat("tt")).toBe("1:23:54 PM");
   expect(dt.reconfigure({ locale: "fr" }).toFormat("tt")).toBe("09:23:54");
   expect(dt.set({ hour: 13 }).reconfigure({ locale: "fr" }).toFormat("tt")).toBe("13:23:54");
 });
@@ -414,16 +414,16 @@ test("DateTime#toFormat('TTT') returns a medium time representation", () => {
 });
 
 test("DateTime#toFormat('f') returns a short date/time representation without seconds", () => {
-  expect(dt.toFormat("f")).toBe("5/25/1982, 9:23 AM");
-  expect(dt.set({ hour: 13 }).toFormat("f")).toBe("5/25/1982, 1:23 PM");
+  expect(dt.toFormat("f")).toBe("5/25/1982, 9:23 AM");
+  expect(dt.set({ hour: 13 }).toFormat("f")).toBe("5/25/1982, 1:23 PM");
   expect(dt.reconfigure({ locale: "fr" }).toFormat("f")).toBe("25/05/1982 09:23");
   expect(dt.set({ hour: 13 }).reconfigure({ locale: "fr" }).toFormat("f")).toBe("25/05/1982 13:23");
 });
 
 test("DateTime#toFormat('ff') returns a medium date/time representation without seconds", () => {
-  expect(dt.toFormat("ff")).toBe("May 25, 1982, 9:23 AM");
-  expect(dt.set({ hour: 13 }).toFormat("ff")).toBe("May 25, 1982, 1:23 PM");
-  expect(dt.set({ month: 8 }).toFormat("ff")).toBe("Aug 25, 1982, 9:23 AM");
+  expect(dt.toFormat("ff")).toBe("May 25, 1982, 9:23 AM");
+  expect(dt.set({ hour: 13 }).toFormat("ff")).toBe("May 25, 1982, 1:23 PM");
+  expect(dt.set({ month: 8 }).toFormat("ff")).toBe("Aug 25, 1982, 9:23 AM");
   expect(dt.reconfigure({ locale: "fr" }).toFormat("ff")).toBe("25 mai 1982, 09:23");
   expect(dt.set({ month: 2 }).reconfigure({ locale: "fr" }).toFormat("ff")).toBe(
     "25 févr. 1982, 09:23"
@@ -434,9 +434,9 @@ test("DateTime#toFormat('ff') returns a medium date/time representation without
 });
 
 test("DateTime#toFormat('fff') returns a medium date/time representation without seconds", () => {
-  expect(ny.toFormat("fff")).toBe("May 25, 1982 at 9:23 AM EDT");
-  expect(ny.set({ hour: 13 }).toFormat("fff")).toBe("May 25, 1982 at 1:23 PM EDT");
-  expect(ny.set({ month: 8 }).toFormat("fff")).toBe("August 25, 1982 at 9:23 AM EDT");
+  expect(ny.toFormat("fff")).toBe("May 25, 1982 at 9:23 AM EDT");
+  expect(ny.set({ hour: 13 }).toFormat("fff")).toBe("May 25, 1982 at 1:23 PM EDT");
+  expect(ny.set({ month: 8 }).toFormat("fff")).toBe("August 25, 1982 at 9:23 AM EDT");
   expect(ny.reconfigure({ locale: "fr" }).toFormat("fff")).toBe("25 mai 1982 à 09:23 UTC−4");
   expect(ny.set({ month: 2 }).reconfigure({ locale: "fr" }).toFormat("fff")).toBe(
     "25 février 1982 à 09:23 UTC−5"
@@ -447,27 +447,27 @@ test("DateTime#toFormat('fff') returns a medium date/time representation without
 });
 
 test("DateTime#toFormat('ffff') returns a long date/time representation without seconds", () => {
-  expect(ny.toFormat("ffff")).toBe("Tuesday, May 25, 1982 at 9:23 AM Eastern Daylight Time");
+  expect(ny.toFormat("ffff")).toBe("Tuesday, May 25, 1982 at 9:23 AM Eastern Daylight Time");
   expect(ny.set({ hour: 13 }).toFormat("ffff")).toBe(
-    "Tuesday, May 25, 1982 at 1:23 PM Eastern Daylight Time"
+    "Tuesday, May 25, 1982 at 1:23 PM Eastern Daylight Time"
   );
   expect(ny.set({ month: 2 }).toFormat("ffff")).toBe(
-    "Thursday, February 25, 1982 at 9:23 AM Eastern Standard Time"
+    "Thursday, February 25, 1982 at 9:23 AM Eastern Standard Time"
   );
   expect(ny.reconfigure({ locale: "fr" }).toFormat("ffff")).toBe(
-    "mardi 25 mai 1982 à 09:23 heure d’été de l’Est"
+    "mardi 25 mai 1982 à 09:23 heure d’été de l’Est nord-américain"
   );
   expect(ny.set({ month: 2 }).reconfigure({ locale: "fr" }).toFormat("ffff")).toBe(
     "jeudi 25 février 1982 à 09:23 heure normale de l’Est nord-américain"
   );
   expect(ny.set({ hour: 13 }).reconfigure({ locale: "fr" }).toFormat("ffff")).toBe(
-    "mardi 25 mai 1982 à 13:23 heure d’été de l’Est"
+    "mardi 25 mai 1982 à 13:23 heure d’été de l’Est nord-américain"
   );
 });
 
 test("DateTime#toFormat('F') returns a short date/time representation with seconds", () => {
-  expect(dt.toFormat("F")).toBe("5/25/1982, 9:23:54 AM");
-  expect(dt.set({ hour: 13 }).toFormat("F")).toBe("5/25/1982, 1:23:54 PM");
+  expect(dt.toFormat("F")).toBe("5/25/1982, 9:23:54 AM");
+  expect(dt.set({ hour: 13 }).toFormat("F")).toBe("5/25/1982, 1:23:54 PM");
   expect(dt.reconfigure({ locale: "fr" }).toFormat("F")).toBe("25/05/1982 09:23:54");
   expect(dt.set({ hour: 13 }).reconfigure({ locale: "fr" }).toFormat("F")).toBe(
     "25/05/1982 13:23:54"
@@ -475,9 +475,9 @@ test("DateTime#toFormat('F') returns a short date/time representation with secon
 });
 
 test("DateTime#toFormat('FF') returns a medium date/time representation with seconds", () => {
-  expect(dt.toFormat("FF")).toBe("May 25, 1982, 9:23:54 AM");
-  expect(dt.set({ hour: 13 }).toFormat("FF")).toBe("May 25, 1982, 1:23:54 PM");
-  expect(dt.set({ month: 8 }).toFormat("FF")).toBe("Aug 25, 1982, 9:23:54 AM");
+  expect(dt.toFormat("FF")).toBe("May 25, 1982, 9:23:54 AM");
+  expect(dt.set({ hour: 13 }).toFormat("FF")).toBe("May 25, 1982, 1:23:54 PM");
+  expect(dt.set({ month: 8 }).toFormat("FF")).toBe("Aug 25, 1982, 9:23:54 AM");
   expect(dt.reconfigure({ locale: "fr" }).toFormat("FF")).toBe("25 mai 1982, 09:23:54");
   expect(dt.set({ month: 2 }).reconfigure({ locale: "fr" }).toFormat("FF")).toBe(
     "25 févr. 1982, 09:23:54"
@@ -488,9 +488,9 @@ test("DateTime#toFormat('FF') returns a medium date/time representation with sec
 });
 
 test("DateTime#toFormat('FFF') returns a medium date/time representation without seconds", () => {
-  expect(ny.toFormat("FFF")).toBe("May 25, 1982 at 9:23:54 AM EDT");
-  expect(ny.set({ hour: 13 }).toFormat("FFF")).toBe("May 25, 1982 at 1:23:54 PM EDT");
-  expect(ny.set({ month: 8 }).toFormat("FFF")).toBe("August 25, 1982 at 9:23:54 AM EDT");
+  expect(ny.toFormat("FFF")).toBe("May 25, 1982 at 9:23:54 AM EDT");
+  expect(ny.set({ hour: 13 }).toFormat("FFF")).toBe("May 25, 1982 at 1:23:54 PM EDT");
+  expect(ny.set({ month: 8 }).toFormat("FFF")).toBe("August 25, 1982 at 9:23:54 AM EDT");
   expect(ny.reconfigure({ locale: "fr" }).toFormat("FFF")).toBe("25 mai 1982 à 9:23:54 UTC−4");
   expect(ny.set({ month: 2 }).reconfigure({ locale: "fr" }).toFormat("FFF")).toBe(
     "25 février 1982 à 9:23:54 UTC−5"
@@ -501,21 +501,21 @@ test("DateTime#toFormat('FFF') returns a medium date/time representation without
 });
 
 test("DateTime#toFormat('FFFF') returns a long date/time representation without seconds", () => {
-  expect(ny.toFormat("FFFF")).toBe("Tuesday, May 25, 1982 at 9:23:54 AM Eastern Daylight Time");
+  expect(ny.toFormat("FFFF")).toBe("Tuesday, May 25, 1982 at 9:23:54 AM Eastern Daylight Time");
   expect(ny.set({ hour: 13 }).toFormat("FFFF")).toBe(
-    "Tuesday, May 25, 1982 at 1:23:54 PM Eastern Daylight Time"
+    "Tuesday, May 25, 1982 at 1:23:54 PM Eastern Daylight Time"
   );
   expect(ny.set({ month: 2 }).toFormat("FFFF")).toBe(
-    "Thursday, February 25, 1982 at 9:23:54 AM Eastern Standard Time"
+    "Thursday, February 25, 1982 at 9:23:54 AM Eastern Standard Time"
   );
   expect(ny.reconfigure({ locale: "fr" }).toFormat("FFFF")).toBe(
-    "mardi 25 mai 1982 à 9:23:54 heure d’été de l’Est"
+    "mardi 25 mai 1982 à 9:23:54 heure d’été de l’Est nord-américain"
   );
   expect(ny.set({ month: 2 }).reconfigure({ locale: "fr" }).toFormat("FFFF")).toBe(
     "jeudi 25 février 1982 à 9:23:54 heure normale de l’Est nord-américain"
   );
   expect(ny.set({ hour: 13 }).reconfigure({ locale: "fr" }).toFormat("FFFF")).toBe(
-    "mardi 25 mai 1982 à 13:23:54 heure d’été de l’Est"
+    "mardi 25 mai 1982 à 13:23:54 heure d’été de l’Est nord-américain"
   );
 });
 
diff --git a/test/datetime/tokenParse.test.js b/test/datetime/tokenParse.test.js
index 1090ff70..9ba0d162 100644
--- a/test/datetime/tokenParse.test.js
+++ b/test/datetime/tokenParse.test.js
@@ -790,6 +790,12 @@ test("DateTime.fromFormat() parses localized macro tokens", () => {
   }
 });
 
+test("DateTime.fromFormat() allows non-breaking white-space to be substituted inside macro-tokens", () => {
+  expect(DateTime.fromFormat("5:54 PM", "t", { locale: "en-US" }).isValid).toBe(true);
+  expect(DateTime.fromFormat("5:54 PM", "t", { locale: "en-US" }).isValid).toBe(true);
+  expect(DateTime.fromFormat("5:54\nPM", "t", { locale: "en-US" }).isValid).toBe(false);
+});
+
 test("DateTime.fromFormat() throws if you don't provide a format", () => {
   expect(() => DateTime.fromFormat("yo")).toThrowError();
 });
diff --git a/test/interval/format.test.js b/test/interval/format.test.js
index c983823b..f15e55f5 100644
--- a/test/interval/format.test.js
+++ b/test/interval/format.test.js
@@ -21,7 +21,7 @@ test("Interval#toString returns an unfriendly string for invalid intervals", ()
 //------
 
 test("Interval#toLocaleString defaults to the DATE_SHORT format", () =>
-  expect(interval.toLocaleString()).toBe("5/25/1982 – 10/14/1983"));
+  expect(interval.toLocaleString()).toBe("5/25/1982 – 10/14/1983"));
 
 test("Interval#toLocaleString returns an unfriendly string for invalid intervals", () =>
   expect(invalid.toLocaleString()).toBe("Invalid Interval"));
@@ -49,7 +49,7 @@ test("Interval#toLocaleString accepts numbering system settings from the start D
       interval.start.reconfigure({ numberingSystem: "beng" }),
       interval.end
     ).toLocaleString()
-  ).toBe("৫/২৫/১৯৮২ – ১০/১৪/১৯৮৩");
+  ).toBe("৫/২৫/১৯৮২ – ১০/১৪/১৯৮৩");
 });
 
 test("Interval#toLocaleString accepts ouptput calendar settings from the start DateTime", () => {
@@ -58,11 +58,11 @@ test("Interval#toLocaleString accepts ouptput calendar settings from the start D
       interval.start.reconfigure({ outputCalendar: "islamic" }),
       interval.end
     ).toLocaleString()
-  ).toBe("8/2/1402 – 1/8/1404 AH");
+  ).toBe("8/2/1402 – 1/8/1404 AH");
 });
 
 test("Interval#toLocaleString accepts options to the formatter", () => {
-  expect(interval.toLocaleString({ weekday: "short" })).toBe("Tue – Fri");
+  expect(interval.toLocaleString({ weekday: "short" })).toBe("Tue – Fri");
 });
 
 test("Interval#toLocaleString can override the start DateTime's locale", () => {
@@ -71,7 +71,7 @@ test("Interval#toLocaleString can override the start DateTime's locale", () => {
       interval.start.reconfigure({ locale: "be" }),
       interval.end
     ).toLocaleString({}, { locale: "fr" })
-  ).toBe("25/05/1982 – 14/10/1983");
+  ).toBe("25/05/1982 – 14/10/1983");
 });
 
 test("Interval#toLocaleString can override the start DateTime's numbering system", () => {
@@ -80,7 +80,7 @@ test("Interval#toLocaleString can override the start DateTime's numbering system
       interval.start.reconfigure({ numberingSystem: "beng" }),
       interval.end
     ).toLocaleString({ numberingSystem: "mong" })
-  ).toBe("᠕/᠒᠕/᠑᠙᠘᠒ – ᠑᠐/᠑᠔/᠑᠙᠘᠓");
+  ).toBe("᠕/᠒᠕/᠑᠙᠘᠒ – ᠑᠐/᠑᠔/᠑᠙᠘᠓");
 });
 
 test("Interval#toLocaleString can override the start DateTime's output calendar", () => {
@@ -89,7 +89,7 @@ test("Interval#toLocaleString can override the start DateTime's output calendar"
       interval.start.reconfigure({ outputCalendar: "islamic" }),
       interval.end
     ).toLocaleString({}, { outputCalendar: "coptic" })
-  ).toBe("9/17/1698 – 2/3/1700 ERA1");
+  ).toBe("9/17/1698 – 2/3/1700 ERA1");
 });
 
 test("Interval#toLocaleString shows things in the right IANA zone", () => {
@@ -98,7 +98,7 @@ test("Interval#toLocaleString shows things in the right IANA zone", () => {
       interval.start.setZone("Australia/Melbourne"),
       interval.end
     ).toLocaleString(DateTime.DATETIME_SHORT)
-  ).toBe("5/25/1982, 7:00 PM – 10/14/1983, 11:30 PM");
+  ).toBe("5/25/1982, 7:00 PM – 10/14/1983, 11:30 PM");
 });
 
 test("Interval#toLocaleString shows things in the right fixed-offset zone", () => {
@@ -106,7 +106,7 @@ test("Interval#toLocaleString shows things in the right fixed-offset zone", () =
     Interval.fromDateTimes(interval.start.setZone("UTC-8"), interval.end).toLocaleString(
       DateTime.DATETIME_SHORT
     )
-  ).toBe("5/25/1982, 1:00 AM – 10/14/1983, 5:30 AM");
+  ).toBe("5/25/1982, 1:00 AM – 10/14/1983, 5:30 AM");
 });
 
 test("Interval#toLocaleString shows things in the right fixed-offset zone when showing the zone", () => {
@@ -114,7 +114,7 @@ test("Interval#toLocaleString shows things in the right fixed-offset zone when s
     Interval.fromDateTimes(interval.start.setZone("UTC-8"), interval.end).toLocaleString(
       DateTime.DATETIME_FULL
     )
-  ).toBe("May 25, 1982 at 1:00 AM GMT-8 – October 14, 1983 at 5:30 AM GMT-8");
+  ).toBe("May 25, 1982 at 1:00 AM GMT-8 – October 14, 1983 at 5:30 AM GMT-8");
 });
 
 test("Interval#toLocaleString shows things with UTC if fixed-offset with 0 offset is used", () => {
@@ -122,7 +122,7 @@ test("Interval#toLocaleString shows things with UTC if fixed-offset with 0 offse
     Interval.fromDateTimes(interval.start.setZone("UTC"), interval.end).toLocaleString(
       DateTime.DATETIME_FULL
     )
-  ).toBe("May 25, 1982 at 9:00 AM UTC – October 14, 1983 at 1:30 PM UTC");
+  ).toBe("May 25, 1982 at 9:00 AM UTC – October 14, 1983 at 1:30 PM UTC");
 });
 
 test("Interval#toLocaleString does the best it can with unsupported fixed-offset zone when showing the zone", () => {
@@ -130,7 +130,7 @@ test("Interval#toLocaleString does the best it can with unsupported fixed-offset
     Interval.fromDateTimes(interval.start.setZone("UTC+4:30"), interval.end).toLocaleString(
       DateTime.DATETIME_FULL
     )
-  ).toBe("May 25, 1982 at 9:00 AM UTC – October 14, 1983 at 1:30 PM UTC");
+  ).toBe("May 25, 1982 at 9:00 AM UTC – October 14, 1983 at 1:30 PM UTC");
 });
 
 test("Interval#toLocaleString uses locale-appropriate time formats", () => {
@@ -138,24 +138,24 @@ test("Interval#toLocaleString uses locale-appropriate time formats", () => {
     Interval.after(interval.start.reconfigure({ locale: "en-US" }), { hour: 2 }).toLocaleString(
       DateTime.TIME_SIMPLE
     )
-  ).toBe("9:00 – 11:00 AM");
+  ).toBe("9:00 – 11:00 AM");
   expect(
     Interval.after(interval.start.reconfigure({ locale: "en-US" }), { hour: 2 }).toLocaleString(
       DateTime.TIME_24_SIMPLE
     )
-  ).toBe("09:00 – 11:00");
+  ).toBe("09:00 – 11:00");
 
   // France has 24-hour by default
   expect(
     Interval.after(interval.start.reconfigure({ locale: "fr" }), { hour: 2 }).toLocaleString(
       DateTime.TIME_SIMPLE
     )
-  ).toBe("09:00 – 11:00");
+  ).toBe("09:00 – 11:00");
   expect(
     Interval.after(interval.start.reconfigure({ locale: "fr" }), { hour: 2 }).toLocaleString(
       DateTime.TIME_24_SIMPLE
     )
-  ).toBe("09:00 – 11:00");
+  ).toBe("09:00 – 11:00");
 
   // Spain does't prefix with "0" and doesn't use spaces
   expect(
@@ -172,7 +172,7 @@ test("Interval#toLocaleString uses locale-appropriate time formats", () => {
 
 test("Interval#toLocaleString sets the separator between days for same-month dates", () => {
   expect(Interval.after(interval.start, { day: 2 }).toLocaleString(DateTime.DATE_MED)).toBe(
-    "May 25 – 27, 1982"
+    "May 25 – 27, 1982"
   );
 });