Repository: moment/luxon
Pull request #1211 (2022-05-19 23:44:33)

Update why.md
I was a bit confused by this, and thought that Safari supported Luxon. But it appears that it now works starting in Safari 14, released in Sep 2020. So updating these docs may help others avoid confusion.

Thanks so much for your work on this library!

linux-foundation-easycla[bot]:  <a href="https://api.easycla.lfx.linuxfoundation.org/v2/repository-provider/github/sign/19772872/47118129/1211/#/?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/1211/#/?version=2' target='_blank'>:x:</a> - login: @mchusma / name: Chris Hawkins . The commit (f8dc95d9a3ebe10c163f53c27abd60c5fab2ebf6) is not authorized under a signed CLA. <a href='https://api.easycla.lfx.linuxfoundation.org/v2/repository-provider/github/sign/19772872/47118129/1211/#/?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/docs/why.md b/docs/why.md
index 93ecaa97..c4265501 100644
--- a/docs/why.md
+++ b/docs/why.md
@@ -48,7 +48,7 @@ They also have some disadvantages:
 
 Luxon lives in the Moment project because, basically, we all really like it, and it represents a huge improvement.
 
-But Luxon doesn't quite fulfill Moment's mandate. Since it sometimes relies on browsers' implementations of the `Intl` specifications, it doesn't provide some of Moment's most commonly-used features on all browsers. Relative date formatting is for instance not supported in IE11 and Safari (as of August 2020). Luxon's Intl features do not work as expected on sufficiently outdated browsers, whereas Moment's all work everywhere. That represents a good tradeoff, IMO, but it's clearly a different one than Moment makes.
+But Luxon doesn't quite fulfill Moment's mandate. Since it sometimes relies on browsers' implementations of the `Intl` specifications, it doesn't provide some of Moment's most commonly-used features on all browsers. Relative date formatting is for instance not supported in IE11 and [other older browsers](https://caniuse.com/?search=Intl%20RelativeTimeFormat). Luxon's Intl features do not work as expected on sufficiently outdated browsers, whereas Moment's all work everywhere. That represents a good tradeoff, IMO, but it's clearly a different one than Moment makes.
 
 Luxon makes a major break in API conventions. Part of Moment's charm is that you just call `moment()` on basically anything and you get date, whereas Luxon forces you to decide that you want to call `fromISO` or whatever. The upshot of all that is that Luxon feels like a different library; that's why it's not Moment 3.0.
 
diff --git a/package-lock.json b/package-lock.json
index 5cb03a3f..48590c35 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -17,9 +17,9 @@
         "@rollup/plugin-commonjs": "^19.0.0",
         "@rollup/plugin-node-resolve": "^13.0.0",
         "babel-jest": "^25.3.0",
-        "benchmark": "latest",
-        "codecov": "latest",
-        "documentation": "latest",
+        "benchmark": "*",
+        "codecov": "*",
+        "documentation": "*",
         "fs-extra": "^6.0.1",
         "husky": "^7.0.0",
         "jest": "^27.0.6",
@@ -6786,7 +6786,7 @@
     "node_modules/filter-obj": {
       "version": "1.1.0",
       "resolved": "https://registry.npmjs.org/filter-obj/-/filter-obj-1.1.0.tgz",
-      "integrity": "sha1-mzERErxsYSehbgFsbF1/GeCAXFs=",
+      "integrity": "sha512-8rXg1ZnX7xzy2NGDVkBVaAy+lSlPNwad13BtgSlLuxfIslyt5Vg64U7tFcCt4WS1R0hvtnQybT/IyCkGZ3DpXQ==",
       "dev": true,
       "engines": {
         "node": ">=0.10.0"
@@ -13743,9 +13743,9 @@
       }
     },
     "node_modules/parse-path": {
-      "version": "4.0.3",
-      "resolved": "https://registry.npmjs.org/parse-path/-/parse-path-4.0.3.tgz",
-      "integrity": "sha512-9Cepbp2asKnWTJ9x2kpw6Fe8y9JDbqwahGCTvklzd/cEq5C5JC59x2Xb0Kx+x0QZ8bvNquGO8/BWP0cwBHzSAA==",
+      "version": "4.0.4",
+      "resolved": "https://registry.npmjs.org/parse-path/-/parse-path-4.0.4.tgz",
+      "integrity": "sha512-Z2lWUis7jlmXC1jeOG9giRO2+FsuyNipeQ43HAjqAZjwSe3SEf+q/84FGPHoso3kyntbxa4c4i77t3m6fGf8cw==",
       "dev": true,
       "dependencies": {
         "is-ssh": "^1.3.0",
@@ -13755,14 +13755,14 @@
       }
     },
     "node_modules/parse-url": {
-      "version": "6.0.0",
-      "resolved": "https://registry.npmjs.org/parse-url/-/parse-url-6.0.0.tgz",
-      "integrity": "sha512-cYyojeX7yIIwuJzledIHeLUBVJ6COVLeT4eF+2P6aKVzwvgKQPndCBv3+yQ7pcWjqToYwaligxzSYNNmGoMAvw==",
+      "version": "6.0.2",
+      "resolved": "https://registry.npmjs.org/parse-url/-/parse-url-6.0.2.tgz",
+      "integrity": "sha512-uCSjOvD3T+6B/sPWhR+QowAZcU/o4bjPrVBQBGFxcDF6J6FraCGIaDBsdoQawiaaAVdHvtqBe3w3vKlfBKySOQ==",
       "dev": true,
       "dependencies": {
         "is-ssh": "^1.3.0",
         "normalize-url": "^6.1.0",
-        "parse-path": "^4.0.0",
+        "parse-path": "^4.0.4",
         "protocols": "^1.4.0"
       }
     },
@@ -16131,7 +16131,7 @@
     "node_modules/strict-uri-encode": {
       "version": "2.0.0",
       "resolved": "https://registry.npmjs.org/strict-uri-encode/-/strict-uri-encode-2.0.0.tgz",
-      "integrity": "sha1-ucczDHBChi9rFC3CdLvMWGbONUY=",
+      "integrity": "sha512-QwiXZgpRcKkhTj2Scnn++4PKtWsH0kpzZ62L2R6c/LUVYv7hVnZqcg2+sMuT6R7Jusu1vviK/MFsu6kNJfWlEQ==",
       "dev": true,
       "engines": {
         "node": ">=4"
@@ -22818,7 +22818,7 @@
     "filter-obj": {
       "version": "1.1.0",
       "resolved": "https://registry.npmjs.org/filter-obj/-/filter-obj-1.1.0.tgz",
-      "integrity": "sha1-mzERErxsYSehbgFsbF1/GeCAXFs=",
+      "integrity": "sha512-8rXg1ZnX7xzy2NGDVkBVaAy+lSlPNwad13BtgSlLuxfIslyt5Vg64U7tFcCt4WS1R0hvtnQybT/IyCkGZ3DpXQ==",
       "dev": true
     },
     "find-cache-dir": {
@@ -28174,9 +28174,9 @@
       "dev": true
     },
     "parse-path": {
-      "version": "4.0.3",
-      "resolved": "https://registry.npmjs.org/parse-path/-/parse-path-4.0.3.tgz",
-      "integrity": "sha512-9Cepbp2asKnWTJ9x2kpw6Fe8y9JDbqwahGCTvklzd/cEq5C5JC59x2Xb0Kx+x0QZ8bvNquGO8/BWP0cwBHzSAA==",
+      "version": "4.0.4",
+      "resolved": "https://registry.npmjs.org/parse-path/-/parse-path-4.0.4.tgz",
+      "integrity": "sha512-Z2lWUis7jlmXC1jeOG9giRO2+FsuyNipeQ43HAjqAZjwSe3SEf+q/84FGPHoso3kyntbxa4c4i77t3m6fGf8cw==",
       "dev": true,
       "requires": {
         "is-ssh": "^1.3.0",
@@ -28186,14 +28186,14 @@
       }
     },
     "parse-url": {
-      "version": "6.0.0",
-      "resolved": "https://registry.npmjs.org/parse-url/-/parse-url-6.0.0.tgz",
-      "integrity": "sha512-cYyojeX7yIIwuJzledIHeLUBVJ6COVLeT4eF+2P6aKVzwvgKQPndCBv3+yQ7pcWjqToYwaligxzSYNNmGoMAvw==",
+      "version": "6.0.2",
+      "resolved": "https://registry.npmjs.org/parse-url/-/parse-url-6.0.2.tgz",
+      "integrity": "sha512-uCSjOvD3T+6B/sPWhR+QowAZcU/o4bjPrVBQBGFxcDF6J6FraCGIaDBsdoQawiaaAVdHvtqBe3w3vKlfBKySOQ==",
       "dev": true,
       "requires": {
         "is-ssh": "^1.3.0",
         "normalize-url": "^6.1.0",
-        "parse-path": "^4.0.0",
+        "parse-path": "^4.0.4",
         "protocols": "^1.4.0"
       }
     },
@@ -30089,7 +30089,7 @@
     "strict-uri-encode": {
       "version": "2.0.0",
       "resolved": "https://registry.npmjs.org/strict-uri-encode/-/strict-uri-encode-2.0.0.tgz",
-      "integrity": "sha1-ucczDHBChi9rFC3CdLvMWGbONUY=",
+      "integrity": "sha512-QwiXZgpRcKkhTj2Scnn++4PKtWsH0kpzZ62L2R6c/LUVYv7hVnZqcg2+sMuT6R7Jusu1vviK/MFsu6kNJfWlEQ==",
       "dev": true
     },
     "string_decoder": {
diff --git a/package.json b/package.json
index a8f3bc48..8d479ddb 100644
--- a/package.json
+++ b/package.json
@@ -14,7 +14,7 @@
     "build-global": "babel-node tasks/buildGlobal.js",
     "jest": "jest",
     "test": "jest --coverage",
-    "api-docs": "mkdir -p build && documentation build src/luxon.js -f html -o build/api-docs && sed -i.bak 's/<\\/body>/<script src=\"\\/global\\/luxon.js\"><\\/script><script>console.log(\"You can try Luxon right here using the `luxon` global, like `luxon.DateTime.now()`\");<\\/script><\\/body>/g' build/api-docs/index.html && rm build/api-docs/index.html.bak",
+    "api-docs": "mkdir -p build && documentation build src/luxon.js -f html -o build/api-docs && sed -i.bak 's/<\\/body>/<script src=\"\\..\\/global\\/luxon.js\"><\\/script><script>console.log(\"You can try Luxon right here using the `luxon` global, like `luxon.DateTime.now()`\");<\\/script><\\/body>/g' build/api-docs/index.html && rm build/api-docs/index.html.bak",
     "copy-site": "mkdir -p build && rsync -a docs/ build/docs && rsync -a site/ build",
     "site": "npm run api-docs && npm run copy-site",
     "format": "prettier --write 'src/**/*.js' 'test/**/*.js' 'benchmarks/*.js'",
diff --git a/src/duration.js b/src/duration.js
index 72c1b197..3be060cf 100644
--- a/src/duration.js
+++ b/src/duration.js
@@ -160,7 +160,7 @@ function normalizeValues(matrix, vals) {
  * Here is a brief overview of commonly used methods and getters in Duration:
  *
  * * **Creation** To create a Duration, use {@link Duration#fromMillis}, {@link Duration#fromObject}, or {@link Duration#fromISO}.
- * * **Unit values** See the {@link Duration#years}, {@link Duration.months}, {@link Duration#weeks}, {@link Duration#days}, {@link Duration#hours}, {@link Duration#minutes}, {@link Duration#seconds}, {@link Duration#milliseconds} accessors.
+ * * **Unit values** See the {@link Duration#years}, {@link Duration#months}, {@link Duration#weeks}, {@link Duration#days}, {@link Duration#hours}, {@link Duration#minutes}, {@link Duration#seconds}, {@link Duration#milliseconds} accessors.
  * * **Configuration** See  {@link Duration#locale} and {@link Duration#numberingSystem} accessors.
  * * **Transformation** To create new Durations out of old ones use {@link Duration#plus}, {@link Duration#minus}, {@link Duration#normalize}, {@link Duration#set}, {@link Duration#reconfigure}, {@link Duration#shiftTo}, and {@link Duration#negate}.
  * * **Output** To convert the Duration into other representations, see {@link Duration#as}, {@link Duration#toISO}, {@link Duration#toFormat}, and {@link Duration#toJSON}
@@ -405,6 +405,7 @@ export default class Duration {
    * * `y` for years
    * Notes:
    * * Add padding by repeating the token, e.g. "yy" pads the years to two digits, "hhhh" pads the hours out to four digits
+   * * Tokens can be escaped by wrapping with single quotes.
    * * The duration will be converted to the set of units in the format string using {@link Duration#shiftTo} and the Durations's conversion accuracy setting.
    * @param {string} fmt - the format string
    * @param {Object} opts - options
diff --git a/src/impl/regexParser.js b/src/impl/regexParser.js
index 0ebd33c8..43689a45 100644
--- a/src/impl/regexParser.js
+++ b/src/impl/regexParser.js
@@ -127,7 +127,7 @@ const isoTimeOnly = RegExp(`^T?${isoTimeBaseRegex.source}$`);
 // ISO duration parsing
 
 const isoDuration =
-  /^-?P(?:(?:(-?\d{1,9}(?:\.\d{1,9})?)Y)?(?:(-?\d{1,9}(?:\.\d{1,9})?)M)?(?:(-?\d{1,9}(?:\.\d{1,9})?)W)?(?:(-?\d{1,9}(?:\.\d{1,9})?)D)?(?:T(?:(-?\d{1,9}(?:\.\d{1,9})?)H)?(?:(-?\d{1,9}(?:\.\d{1,9})?)M)?(?:(-?\d{1,20})(?:[.,](-?\d{1,9}))?S)?)?)$/;
+  /^-?P(?:(?:(-?\d{1,20}(?:\.\d{1,20})?)Y)?(?:(-?\d{1,20}(?:\.\d{1,20})?)M)?(?:(-?\d{1,20}(?:\.\d{1,20})?)W)?(?:(-?\d{1,20}(?:\.\d{1,20})?)D)?(?:T(?:(-?\d{1,20}(?:\.\d{1,20})?)H)?(?:(-?\d{1,20}(?:\.\d{1,20})?)M)?(?:(-?\d{1,20})(?:[.,](-?\d{1,20}))?S)?)?)$/;
 
 function extractISODuration(match) {
   const [s, yearStr, monthStr, weekStr, dayStr, hourStr, minuteStr, secondStr, millisecondsStr] =
@@ -234,7 +234,7 @@ function preprocessRFC2822(s) {
 const rfc1123 =
     /^(Mon|Tue|Wed|Thu|Fri|Sat|Sun), (\d\d) (Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec) (\d{4}) (\d\d):(\d\d):(\d\d) GMT$/,
   rfc850 =
-    /^(Monday|Tuesday|Wedsday|Thursday|Friday|Saturday|Sunday), (\d\d)-(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)-(\d\d) (\d\d):(\d\d):(\d\d) GMT$/,
+    /^(Monday|Tuesday|Wednesday|Thursday|Friday|Saturday|Sunday), (\d\d)-(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)-(\d\d) (\d\d):(\d\d):(\d\d) GMT$/,
   ascii =
     /^(Mon|Tue|Wed|Thu|Fri|Sat|Sun) (Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec) ( \d|\d\d) (\d\d):(\d\d):(\d\d) (\d{4})$/;
 


Test patch:
diff --git a/test/datetime/regexParse.test.js b/test/datetime/regexParse.test.js
index c297c0f9..db8ee530 100644
--- a/test/datetime/regexParse.test.js
+++ b/test/datetime/regexParse.test.js
@@ -814,6 +814,20 @@ test("DateTime.fromHTTP() can parse RFC 850", () => {
   });
 });
 
+test("DateTime.fromHTTP() can parse RFC 850 on Wednesday", () => {
+  const dt = DateTime.fromHTTP("Wednesday, 29-Jun-22 08:49:37 GMT");
+  expect(dt.isValid).toBe(true);
+  expect(dt.toUTC().toObject()).toEqual({
+    year: 2022,
+    month: 6,
+    day: 29,
+    hour: 8,
+    minute: 49,
+    second: 37,
+    millisecond: 0,
+  });
+});
+
 test("DateTime.fromHTTP() can parse ASCII dates with one date digit", () => {
   const dt = DateTime.fromHTTP("Sun Nov  6 08:49:37 1994");
   expect(dt.isValid).toBe(true);