Repository: moment/luxon
Pull request #1546 (2023-11-28 18:27:26)

Alias DateTime in documentation site
All examples use `DateTime`. The install guide even suggests doing the alias.

The first thing I tried was to copy the example on the landing page `DateTime.now().setZone('America/New_York').minus({weeks:1}).endOf('day').toISO();`
->
`Uncaught ReferenceError: DateTime is not defined at <anonymous>:1:1`


linux-foundation-easycla[bot]:  <a href="https://api.easycla.lfx.linuxfoundation.org/v2/repository-provider/github/sign/19772872/47118129/1546/#/?version=2"><img src="https://s3.amazonaws.com/cla-project-logo-prod/cla-not-signed.svg" alt="CLA Not Signed" align="left" height="28" width="328"></a><br/><br /><ul><li><a href='https://api.easycla.lfx.linuxfoundation.org/v2/repository-provider/github/sign/19772872/47118129/1546/#/?version=2' target='_blank'>:x:</a> - login: @forgotPassword . The commit (ed8189dc4d0822f4f324cd420146cbda5b0dddd7) is not authorized under a signed CLA. <a href='https://api.easycla.lfx.linuxfoundation.org/v2/repository-provider/github/sign/19772872/47118129/1546/#/?version=2' target='_blank'>Please click here to be authorized</a>. For further assistance with EasyCLA, <a href='https://jira.linuxfoundation.org/servicedesk/customer/portal/4' target='_blank'>please submit a support request ticket</a>.</li></ul>

Patch:
diff --git a/benchmarks/datetime.js b/benchmarks/datetime.js
index 39d6bf07..f4dffda7 100644
--- a/benchmarks/datetime.js
+++ b/benchmarks/datetime.js
@@ -8,8 +8,10 @@ function runDateTimeSuite() {
 
     const dt = DateTime.now();
 
+    const formatParser = DateTime.buildFormatParser("yyyy/MM/dd HH:mm:ss.SSS");
+
     suite
-      .add("DateTime.local", () => {
+      .add("DateTime.now", () => {
         DateTime.now();
       })
       .add("DateTime.fromObject with locale", () => {
@@ -18,6 +20,9 @@ function runDateTimeSuite() {
       .add("DateTime.local with numbers", () => {
         DateTime.local(2017, 5, 15);
       })
+      .add("DateTime.local with numbers and zone", () => {
+        DateTime.local(2017, 5, 15, 11, 7, 35, { zone: "America/New_York" });
+      })
       .add("DateTime.fromISO", () => {
         DateTime.fromISO("1982-05-25T09:10:11.445Z");
       })
@@ -32,6 +37,14 @@ function runDateTimeSuite() {
           zone: "America/Los_Angeles",
         });
       })
+      .add("DateTime.fromFormatParser", () => {
+        DateTime.fromFormatParser("1982/05/25 09:10:11.445", formatParser);
+      })
+      .add("DateTime.fromFormatParser with zone", () => {
+        DateTime.fromFormatParser("1982/05/25 09:10:11.445", formatParser, {
+          zone: "America/Los_Angeles",
+        });
+      })
       .add("DateTime#setZone", () => {
         dt.setZone("America/Los_Angeles");
       })
diff --git a/docs/formatting.md b/docs/formatting.md
index 6ad02c3e..b266520c 100644
--- a/docs/formatting.md
+++ b/docs/formatting.md
@@ -86,27 +86,28 @@ dt.toLocaleString(newFormat); //=>  'Thursday, 4/20/2017'
 
 Here's the full set of provided presets using the October 14, 1983 at `13:30:23` as an example.
 
-| Name                         | Description                                                        | Example in en_US                                             | Example in fr                                              |
-| ---------------------------- | ------------------------------------------------------------------ | ------------------------------------------------------------ | ---------------------------------------------------------- |
-| `DATE_SHORT`                 | short date                                                         | `10/14/1983`                                                 | `14/10/1983`                                               |
-| `DATE_MED`                   | abbreviated date                                                   | `Oct 14, 1983`                                               | `14 oct. 1983`                                             |
-| `DATE_MED_WITH_WEEKDAY`      | abbreviated date with abbreviated weekday                          | `Fri, Oct 14, 1983`                                          | `ven. 14 oct. 1983`                                             |
-| `DATE_FULL`                  | full date                                                          | `October 14, 1983`                                           | `14 octobre 1983`                                          |
-| `DATE_HUGE`                  | full date with weekday                                             | `Friday, October 14, 1983`                                   | `vendredi 14 octobre 1983`                                 |
-| `TIME_SIMPLE`                | time                                                               | `1:30 PM`                                                    | `13:30`                                                    |
-| `TIME_WITH_SECONDS`          | time with seconds                                                  | `1:30:23 PM`                                                 | `13:30:23`                                                 |
-| `TIME_WITH_SHORT_OFFSET`     | time with seconds and abbreviated named offset                     | `1:30:23 PM EDT`                                             | `13:30:23 UTC−4`                                           |
-| `TIME_WITH_LONG_OFFSET`      | time with seconds and full named offset                            | `1:30:23 PM Eastern Daylight Time`                           | `13:30:23 heure d’été de l’Est`                            |
-| `TIME_24_SIMPLE`             | 24-hour time                                                       | `13:30`                                                      | `13:30`                                                    |
-| `TIME_24_WITH_SECONDS`       | 24-hour time with seconds                                          | `13:30:23`                                                   | `13:30:23`                                                 |
-| `TIME_24_WITH_SHORT_OFFSET`  | 24-hour time with seconds and abbreviated named offset             | `13:30:23 EDT`                                               | `13:30:23 UTC−4`                                           |
-| `TIME_24_WITH_LONG_OFFSET`   | 24-hour time with seconds and full named offset                    | `13:30:23 Eastern Daylight Time`                             | `13:30:23 heure d’été de l’Est`                            |
-| `DATETIME_SHORT`             | short date & time                                                  | `10/14/1983, 1:30 PM`                                        | `14/10/1983 à 13:30`                                       |
-| `DATETIME_MED`               | abbreviated date & time                                            | `Oct 14, 1983, 1:30 PM`                                      | `14 oct. 1983 à 13:30`                                     |
+| Name                         | Description                                                        | Example in en_US                                               | Example in fr                                              |
+| ---------------------------- | ------------------------------------------------------------------ | -------------------------------------------------------------- | ---------------------------------------------------------- |
+| `DATE_SHORT`                 | short date                                                         | `10/14/1983`                                                   | `14/10/1983`                                               |
+| `DATE_MED`                   | abbreviated date                                                   | `Oct 14, 1983`                                                 | `14 oct. 1983`                                             |
+| `DATE_MED_WITH_WEEKDAY`      | abbreviated date with abbreviated weekday                          | `Fri, Oct 14, 1983`                                            | `ven. 14 oct. 1983`                                        |
+| `DATE_FULL`                  | full date                                                          | `October 14, 1983`                                             | `14 octobre 1983`                                          |
+| `DATE_HUGE`                  | full date with weekday                                             | `Friday, October 14, 1983`                                     | `vendredi 14 octobre 1983`                                 |
+| `TIME_SIMPLE`                | time                                                               | `1:30 PM`                                                      | `13:30`                                                    |
+| `TIME_WITH_SECONDS`          | time with seconds                                                  | `1:30:23 PM`                                                   | `13:30:23`                                                 |
+| `TIME_WITH_SHORT_OFFSET`     | time with seconds and abbreviated named offset                     | `1:30:23 PM EDT`                                               | `13:30:23 UTC−4`                                           |
+| `TIME_WITH_LONG_OFFSET`      | time with seconds and full named offset                            | `1:30:23 PM Eastern Daylight Time`                             | `13:30:23 heure d’été de l’Est`                            |
+| `TIME_24_SIMPLE`             | 24-hour time                                                       | `13:30`                                                        | `13:30`                                                    |
+| `TIME_24_WITH_SECONDS`       | 24-hour time with seconds                                          | `13:30:23`                                                     | `13:30:23`                                                 |
+| `TIME_24_WITH_SHORT_OFFSET`  | 24-hour time with seconds and abbreviated named offset             | `13:30:23 EDT`                                                 | `13:30:23 UTC−4`                                           |
+| `TIME_24_WITH_LONG_OFFSET`   | 24-hour time with seconds and full named offset                    | `13:30:23 Eastern Daylight Time`                               | `13:30:23 heure d’été de l’Est`                            |
+| `DATETIME_SHORT`             | short date & time                                                  | `10/14/1983, 1:30 PM`                                          | `14/10/1983 à 13:30`                                       |
+| `DATETIME_MED`               | abbreviated date & time                                            | `Oct 14, 1983, 1:30 PM`                                        | `14 oct. 1983 à 13:30`                                     |
+| `DATETIME_MED_WITH_WEEKDAY`  | abbreviated date & time with abbreviated weekday                   | `Fri, Oct 14, 1983, 1:30 PM`                                   | `ven. 14 oct. 1983 à 13:30`                                |
 | `DATETIME_FULL`              | full date and time with abbreviated named offset                   | `October 14, 1983 at 1:30 PM EDT`                              | `14 octobre 1983 à 13:30 UTC−4`                            |
 | `DATETIME_HUGE`              | full date and time with weekday and full named offset              | `Friday, October 14, 1983 at 1:30 PM Eastern Daylight Time`    | `vendredi 14 octobre 1983 à 13:30 heure d’été de l’Est`    |
-| `DATETIME_SHORT_WITH_SECONDS`| short date & time with seconds                                     | `10/14/1983, 1:30:23 PM`                                     | `14/10/1983 à 13:30:23`                                    |
-| `DATETIME_MED_WITH_SECONDS`  | abbreviated date & time with seconds                               | `Oct 14, 1983, 1:30:23 PM`                                   | `14 oct. 1983 à 13:30:23`                                  |
+| `DATETIME_SHORT_WITH_SECONDS`| short date & time with seconds                                     | `10/14/1983, 1:30:23 PM`                                       | `14/10/1983 à 13:30:23`                                    |
+| `DATETIME_MED_WITH_SECONDS`  | abbreviated date & time with seconds                               | `Oct 14, 1983, 1:30:23 PM`                                     | `14 oct. 1983 à 13:30:23`                                  |
 | `DATETIME_FULL_WITH_SECONDS` | full date and time with abbreviated named offset with seconds      | `October 14, 1983 at 1:30:23 PM EDT`                           | `14 octobre 1983 à 13:30:23 UTC−4`                         |
 | `DATETIME_HUGE_WITH_SECONDS` | full date and time with weekday and full named offset with seconds | `Friday, October 14, 1983 at 1:30:23 PM Eastern Daylight Time` | `vendredi 14 octobre 1983 à 13:30:23 heure d’été de l’Est` |
 
diff --git a/site/index.html b/site/index.html
index d44cfb86..98f9527a 100644
--- a/site/index.html
+++ b/site/index.html
@@ -26,6 +26,7 @@
   <script src="https://unpkg.com/docsify/lib/plugins/search.min.js"></script>
   <script src="global/luxon.js"></script>
   <script>
+    var DateTime = luxon.DateTime;
     console.log(
       "You can try Luxon right here using the `luxon` global, like `luxon.DateTime.now()`."
     );
diff --git a/src/datetime.js b/src/datetime.js
index 9472cb53..5314a9b3 100644
--- a/src/datetime.js
+++ b/src/datetime.js
@@ -28,6 +28,7 @@ import {
   explainFromTokens,
   formatOptsToTokens,
   expandMacroTokens,
+  TokenParser,
 } from "./impl/tokenParser.js";
 import {
   gregorianToWeek,
@@ -373,8 +374,12 @@ function normalizeUnitWithLocalWeeks(unit) {
 // but doesn't do any validation, makes a bunch of assumptions about what units
 // are present, and so on.
 function quickDT(obj, opts) {
-  const zone = normalizeZone(opts.zone, Settings.defaultZone),
-    loc = Locale.fromObject(opts),
+  const zone = normalizeZone(opts.zone, Settings.defaultZone);
+  if (!zone.isValid) {
+    return DateTime.invalid(unsupportedZone(zone));
+  }
+
+  const loc = Locale.fromObject(opts),
     tsNow = Settings.now();
 
   let ts, o;
@@ -487,7 +492,9 @@ export default class DateTime {
       if (unchanged) {
         [c, o] = [config.old.c, config.old.o];
       } else {
-        const ot = zone.offset(this.ts);
+        // If an offset has been passed and we have not been called from
+        // clone(), we can trust it and avoid the offset calculation.
+        const ot = isNumber(config.o) && !config.old ? config.o : zone.offset(this.ts);
         c = tsToObj(this.ts, ot);
         invalid = Number.isNaN(c.year) ? new Invalid("invalid input") : null;
         c = invalid ? null : c;
@@ -2229,6 +2236,74 @@ export default class DateTime {
     return DateTime.fromFormatExplain(text, fmt, options);
   }
 
+  /**
+   * Build a parser for `fmt` using the given locale. This parser can be passed
+   * to {@link DateTime.fromFormatParser} to a parse a date in this format. This
+   * can be used to optimize cases where many dates need to be parsed in a
+   * specific format.
+   *
+   * @param {String} fmt - the format the string is expected to be in (see
+   * description)
+   * @param {Object} options - options used to set locale and numberingSystem
+   * for parser
+   * @returns {TokenParser} - opaque object to be used
+   */
+  static buildFormatParser(fmt, options = {}) {
+    const { locale = null, numberingSystem = null } = options,
+      localeToUse = Locale.fromOpts({
+        locale,
+        numberingSystem,
+        defaultToEN: true,
+      });
+    return new TokenParser(localeToUse, fmt);
+  }
+
+  /**
+   * Create a DateTime from an input string and format parser.
+   *
+   * The format parser must have been created with the same locale as this call.
+   *
+   * @param {String} text - the string to parse
+   * @param {TokenParser} formatParser - parser from {@link DateTime.buildFormatParser}
+   * @param {Object} opts - options taken by fromFormat()
+   * @returns {DateTime}
+   */
+  static fromFormatParser(text, formatParser, opts = {}) {
+    if (isUndefined(text) || isUndefined(formatParser)) {
+      throw new InvalidArgumentError(
+        "fromFormatParser requires an input string and a format parser"
+      );
+    }
+    const { locale = null, numberingSystem = null } = opts,
+      localeToUse = Locale.fromOpts({
+        locale,
+        numberingSystem,
+        defaultToEN: true,
+      });
+
+    if (!localeToUse.equals(formatParser.locale)) {
+      throw new InvalidArgumentError(
+        `fromFormatParser called with a locale of ${localeToUse}, ` +
+          `but the format parser was created for ${formatParser.locale}`
+      );
+    }
+
+    const { result, zone, specificOffset, invalidReason } = formatParser.explainFromTokens(text);
+
+    if (invalidReason) {
+      return DateTime.invalid(invalidReason);
+    } else {
+      return parseDataToDateTime(
+        result,
+        zone,
+        opts,
+        `format ${formatParser.format}`,
+        text,
+        specificOffset
+      );
+    }
+  }
+
   // FORMAT PRESETS
 
   /**
diff --git a/src/impl/digits.js b/src/impl/digits.js
index 6ac1bae0..c8c68af0 100644
--- a/src/impl/digits.js
+++ b/src/impl/digits.js
@@ -70,6 +70,21 @@ export function parseDigits(str) {
   }
 }
 
+// cache of {numberingSystem: {append: regex}}
+let digitRegexCache = {};
+export function resetDigitRegexCache() {
+  digitRegexCache = {};
+}
+
 export function digitRegex({ numberingSystem }, append = "") {
-  return new RegExp(`${numberingSystems[numberingSystem || "latn"]}${append}`);
+  const ns = numberingSystem || "latn";
+
+  if (!digitRegexCache[ns]) {
+    digitRegexCache[ns] = {};
+  }
+  if (!digitRegexCache[ns][append]) {
+    digitRegexCache[ns][append] = new RegExp(`${numberingSystems[ns]}${append}`);
+  }
+
+  return digitRegexCache[ns][append];
 }
diff --git a/src/impl/locale.js b/src/impl/locale.js
index f1caf149..cd55b3bf 100644
--- a/src/impl/locale.js
+++ b/src/impl/locale.js
@@ -539,4 +539,8 @@ export default class Locale {
       this.outputCalendar === other.outputCalendar
     );
   }
+
+  toString() {
+    return `Locale(${this.locale}, ${this.numberingSystem}, ${this.outputCalendar})`;
+  }
 }
diff --git a/src/impl/tokenParser.js b/src/impl/tokenParser.js
index 8dd38f37..48a7595e 100644
--- a/src/impl/tokenParser.js
+++ b/src/impl/tokenParser.js
@@ -432,27 +432,59 @@ export function expandMacroTokens(tokens, locale) {
  * @private
  */
 
-export function explainFromTokens(locale, input, format) {
-  const tokens = expandMacroTokens(Formatter.parseFormat(format), locale),
-    units = tokens.map((t) => unitForToken(t, locale)),
-    disqualifyingUnit = units.find((t) => t.invalidReason);
+export class TokenParser {
+  constructor(locale, format) {
+    this.locale = locale;
+    this.format = format;
+    this.tokens = expandMacroTokens(Formatter.parseFormat(format), locale);
+    this.units = this.tokens.map((t) => unitForToken(t, locale));
+    this.disqualifyingUnit = this.units.find((t) => t.invalidReason);
+
+    if (!this.disqualifyingUnit) {
+      const [regexString, handlers] = buildRegex(this.units);
+      this.regex = RegExp(regexString, "i");
+      this.handlers = handlers;
+    }
+  }
 
-  if (disqualifyingUnit) {
-    return { input, tokens, invalidReason: disqualifyingUnit.invalidReason };
-  } else {
-    const [regexString, handlers] = buildRegex(units),
-      regex = RegExp(regexString, "i"),
-      [rawMatches, matches] = match(input, regex, handlers),
-      [result, zone, specificOffset] = matches
-        ? dateTimeFromMatches(matches)
-        : [null, null, undefined];
-    if (hasOwnProperty(matches, "a") && hasOwnProperty(matches, "H")) {
-      throw new ConflictingSpecificationError(
-        "Can't include meridiem when specifying 24-hour format"
-      );
+  explainFromTokens(input) {
+    if (!this.isValid) {
+      return { input, tokens: this.tokens, invalidReason: this.invalidReason };
+    } else {
+      const [rawMatches, matches] = match(input, this.regex, this.handlers),
+        [result, zone, specificOffset] = matches
+          ? dateTimeFromMatches(matches)
+          : [null, null, undefined];
+      if (hasOwnProperty(matches, "a") && hasOwnProperty(matches, "H")) {
+        throw new ConflictingSpecificationError(
+          "Can't include meridiem when specifying 24-hour format"
+        );
+      }
+      return {
+        input,
+        tokens: this.tokens,
+        regex: this.regex,
+        rawMatches,
+        matches,
+        result,
+        zone,
+        specificOffset,
+      };
     }
-    return { input, tokens, regex, rawMatches, matches, result, zone, specificOffset };
   }
+
+  get isValid() {
+    return !this.disqualifyingUnit;
+  }
+
+  get invalidReason() {
+    return this.disqualifyingUnit ? this.disqualifyingUnit.invalidReason : null;
+  }
+}
+
+export function explainFromTokens(locale, input, format) {
+  const parser = new TokenParser(locale, format);
+  return parser.explainFromTokens(input);
 }
 
 export function parseFromTokens(locale, input, format) {
diff --git a/src/interval.js b/src/interval.js
index dfb58d06..6073d028 100644
--- a/src/interval.js
+++ b/src/interval.js
@@ -405,7 +405,7 @@ export default class Interval {
   }
 
   /**
-   * Return whether this Interval engulfs the start and end of the specified Interval.
+   * Returns true if this Interval fully contains the specified Interval, specifically if the intersect (of this Interval and the other Interval) is equal to the other Interval; false otherwise.
    * @param {Interval} other
    * @return {boolean}
    */
diff --git a/src/settings.js b/src/settings.js
index 462e71e6..f109708d 100644
--- a/src/settings.js
+++ b/src/settings.js
@@ -4,6 +4,7 @@ import Locale from "./impl/locale.js";
 
 import { normalizeZone } from "./impl/zoneUtil.js";
 import { validateWeekSettings } from "./impl/util.js";
+import { resetDigitRegexCache } from "./impl/digits.js";
 
 let now = () => Date.now(),
   defaultZone = "system",
@@ -171,5 +172,6 @@ export default class Settings {
   static resetCaches() {
     Locale.resetCache();
     IANAZone.resetCache();
+    resetDigitRegexCache();
   }
 }


Test patch:
diff --git a/test/datetime/invalid.test.js b/test/datetime/invalid.test.js
index d13fb864..2fed5bbd 100644
--- a/test/datetime/invalid.test.js
+++ b/test/datetime/invalid.test.js
@@ -5,7 +5,11 @@ import { DateTime, Settings } from "../../src/luxon";
 const organic1 = DateTime.utc(2014, 13, 33),
   // not an actual Wednesday
   organic2 = DateTime.fromObject({ weekday: 3, year: 1982, month: 5, day: 25 }, { zone: "UTC" }),
-  organic3 = DateTime.fromObject({ year: 1982, month: 5, day: 25, hour: 27 });
+  organic3 = DateTime.fromObject({ year: 1982, month: 5, day: 25, hour: 27 }),
+  organic4 = DateTime.fromObject(
+    { year: 1982, month: 5, day: 25, hour: 2 },
+    { zone: "America/Lasers" }
+  );
 
 test("Explicitly invalid dates are invalid", () => {
   const dt = DateTime.invalid("just because", "seriously, just because");
@@ -22,14 +26,28 @@ test("Invalid creations are invalid", () => {
 
 test("invalid zones result in invalid dates", () => {
   expect(DateTime.now().setZone("America/Lasers").isValid).toBe(false);
+  expect(DateTime.now().setZone("America/Lasers").invalidReason).toBe("unsupported zone");
+
   expect(DateTime.local({ zone: "America/Lasers" }).isValid).toBe(false);
+  expect(DateTime.local({ zone: "America/Lasers" }).invalidReason).toBe("unsupported zone");
+
+  expect(DateTime.local(1982, { zone: "America/Lasers" }).isValid).toBe(false);
+  expect(DateTime.local(1982, { zone: "America/Lasers" }).invalidReason).toBe("unsupported zone");
+
   expect(DateTime.fromJSDate(new Date(), { zone: "America/Lasers" }).isValid).toBe(false);
+  expect(DateTime.fromJSDate(new Date(), { zone: "America/Lasers" }).invalidReason).toBe(
+    "unsupported zone"
+  );
+
+  expect(DateTime.fromMillis(0, { zone: "America/Lasers" }).isValid).toBe(false);
+  expect(DateTime.fromMillis(0, { zone: "America/Lasers" }).invalidReason).toBe("unsupported zone");
 });
 
 test("Invalid DateTimes tell you why", () => {
   expect(organic1.invalidReason).toBe("unit out of range");
   expect(organic2.invalidReason).toBe("mismatched weekday");
   expect(organic3.invalidReason).toBe("unit out of range");
+  expect(organic4.invalidReason).toBe("unsupported zone");
 });
 
 test("Invalid DateTimes can provide an extended explanation", () => {
diff --git a/test/datetime/proto.test.js b/test/datetime/proto.test.js
index bbe132dc..e3c7bd03 100644
--- a/test/datetime/proto.test.js
+++ b/test/datetime/proto.test.js
@@ -4,6 +4,8 @@ import { DateTime } from "../../src/luxon";
 test("DateTime prototype properties should not throw when accessed", () => {
   const d = DateTime.now();
   expect(() =>
-    Object.getOwnPropertyNames(d.__proto__).forEach((name) => d.__proto__[name])
+    Object.getOwnPropertyNames(Object.getPrototypeOf(d)).forEach(
+      (name) => Object.getPrototypeOf(d)[name]
+    )
   ).not.toThrow();
 });
diff --git a/test/datetime/tokenParse.test.js b/test/datetime/tokenParse.test.js
index 4025821d..8b5c6a8d 100644
--- a/test/datetime/tokenParse.test.js
+++ b/test/datetime/tokenParse.test.js
@@ -1224,3 +1224,28 @@ test("DateTime.expandFormat respects the hour cycle when forced by the macro tok
   const format = DateTime.expandFormat("T", { locale: "en-US" });
   expect(format).toBe("H:m");
 });
+
+//------
+// .fromFormatParser
+//-------
+
+test("DateTime.fromFormatParser behaves equivalently to DateTime.fromFormat", () => {
+  const dateTimeStr = "1982/05/25 09:10:11.445";
+  const format = "yyyy/MM/dd HH:mm:ss.SSS";
+  const formatParser = DateTime.buildFormatParser(format);
+  const ff1 = DateTime.fromFormat(dateTimeStr, format),
+    ffP1 = DateTime.fromFormatParser(dateTimeStr, formatParser);
+
+  expect(ffP1).toEqual(ff1);
+  expect(ffP1.isValid).toBe(true);
+});
+
+test("DateTime.fromFormatParser throws error when used with a different locale than it was created with", () => {
+  const format = "yyyy/MM/dd HH:mm:ss.SSS";
+  const formatParser = DateTime.buildFormatParser(format, { locale: "es-ES" });
+  expect(() =>
+    DateTime.fromFormatParser("1982/05/25 09:10:11.445", formatParser, { locale: "es-MX" })
+  ).toThrowError(
+    "fromFormatParser called with a locale of Locale(es-MX, null, null), but the format parser was created for Locale(es-ES, null, null)"
+  );
+});
diff --git a/test/duration/proto.test.js b/test/duration/proto.test.js
index aba74c4f..2b424db0 100644
--- a/test/duration/proto.test.js
+++ b/test/duration/proto.test.js
@@ -3,6 +3,8 @@ import { Duration } from "../../src/luxon";
 test("Duration prototype properties should not throw when addressed", () => {
   const d = Duration.fromObject({ hours: 1 });
   expect(() =>
-    Object.getOwnPropertyNames(d.__proto__).forEach((name) => d.__proto__[name])
+    Object.getOwnPropertyNames(Object.getPrototypeOf(d)).forEach(
+      (name) => Object.getPrototypeOf(d)[name]
+    )
   ).not.toThrow();
 });
diff --git a/test/interval/proto.test.js b/test/interval/proto.test.js
index bcc3e9b3..831d86ef 100644
--- a/test/interval/proto.test.js
+++ b/test/interval/proto.test.js
@@ -4,6 +4,8 @@ import { DateTime } from "../../src/luxon";
 test("Interval prototype properties should not throw when addressed", () => {
   const i = DateTime.fromISO("2018-01-01").until(DateTime.fromISO("2018-01-02"));
   expect(() =>
-    Object.getOwnPropertyNames(i.__proto__).forEach((name) => i.__proto__[name])
+    Object.getOwnPropertyNames(Object.getPrototypeOf(i)).forEach(
+      (name) => Object.getPrototypeOf(i)[name]
+    )
   ).not.toThrow();
 });