Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

luxon

Package Overview
Dependencies
Maintainers
1
Versions
145
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

luxon - npm Package Compare versions

Comparing version 1.28.1 to 3.4.0

build/es6/luxon.js

79

package.json
{
"name": "luxon",
"version": "1.28.1",
"version": "3.4.0",
"description": "Immutable date wrapper",

@@ -11,2 +11,9 @@ "author": "Isaac Cambron",

"repository": "https://github.com/moment/luxon",
"exports": {
".": {
"import": "./src/luxon.js",
"require": "./build/node/luxon.js"
},
"./package.json": "./package.json"
},
"scripts": {

@@ -18,16 +25,12 @@ "build": "babel-node tasks/buildAll.js",

"test": "jest --coverage",
"docs": "esdoc -c docs/index.js",
"site": "cp -r site/** build/",
"lint": "eslint --quiet src test benchmarks",
"lint!": "npm run format && npm run lint",
"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'",
"format-check": "prettier --check 'src/**/*.js' 'test/**/*.js' 'benchmarks/*.js'",
"benchmark": "babel-node benchmarks/index.js",
"codecov": "codecov",
"check-doc-coverage": "babel-node tasks/docCoverage"
"prepack": "babel-node tasks/buildAll.js",
"prepare": "husky install"
},
"husky": {
"hooks": {
"pre-commit": "lint-staged"
}
},
"lint-staged": {

@@ -39,37 +42,21 @@ "*.{js,json}": [

"devDependencies": {
"@babel/core": "^7.9.0",
"@babel/node": "^7.8.7",
"@babel/plugin-external-helpers": "^7.8.3",
"@babel/preset-env": "^7.9.5",
"@rollup/plugin-commonjs": "^11.1.0",
"@rollup/plugin-node-resolve": "^7.1.3",
"babel-core": "^7.0.0-bridge.0",
"babel-eslint": "latest",
"babel-jest": "^25.3.0",
"@babel/core": "^7.18.6",
"@babel/node": "^7.18.6",
"@babel/plugin-external-helpers": "^7.18.6",
"@babel/preset-env": "^7.18.6",
"@rollup/plugin-babel": "^5.3.0",
"@rollup/plugin-commonjs": "^19.0.0",
"@rollup/plugin-node-resolve": "^13.0.0",
"babel-jest": "^28.1.2",
"benchmark": "latest",
"codecov": ">= 3.6.5",
"core-js": "^3.6.5",
"esdoc": "^1.1.0",
"esdoc-standard-plugin": "latest",
"eslint": "6.4.0",
"eslint-config-defaults": "latest",
"eslint-config-prettier": "6.3.0",
"eslint-config-standard": "^14.1.1",
"eslint-plugin-babel": "latest",
"eslint-plugin-import": "^2.20.2",
"eslint-plugin-node": "10.0.0",
"eslint-plugin-prettier": "3.1.1",
"eslint-plugin-promise": "latest",
"eslint-plugin-react": "^7.19.0",
"eslint-plugin-standard": "^4.0.1",
"codecov": "latest",
"documentation": "latest",
"fs-extra": "^6.0.1",
"full-icu": "^1.3.1",
"husky": "^4.2.5",
"jest": "^25.3.0",
"lint-staged": "^10.1.3",
"prettier": "1.14.3",
"rollup": "^1.32.1",
"rollup-plugin-babel": "^4.4.0",
"rollup-plugin-babel-minify": "^6.2.0",
"uglify-es": "^3.3.9"
"husky": "^7.0.0",
"jest": "^29.4.3",
"lint-staged": "^13.2.1",
"prettier": "latest",
"rollup": "^2.52.7",
"rollup-plugin-terser": "^7.0.2",
"uglify-js": "^3.13.10"
},

@@ -82,3 +69,3 @@ "main": "build/node/luxon.js",

"engines": {
"node": "*"
"node": ">=12"
},

@@ -96,2 +83,4 @@ "files": [

"build/global/luxon.min.js.map",
"build/es6/luxon.js",
"build/es6/luxon.js.map",
"src"

@@ -98,0 +87,0 @@ ],

# Luxon
[![MIT License][license-image]][license] [![Build Status][travis-image]][travis-url] [![NPM version][npm-version-image]][npm-url] [![Coverage Status][test-coverage-image]][test-coverage-url] [![Doc coverage][doc-coverage-image]][doc-url] [![PRs welcome][contributing-image]][contributing-url]
[![MIT License][license-image]][license] [![Build Status][github-action-image]][github-action-url] [![NPM version][npm-version-image]][npm-url] [![Coverage Status][test-coverage-image]][test-coverage-url] [![PRs welcome][contributing-image]][contributing-url]

@@ -11,2 +11,6 @@ Luxon is a library for working with dates and times in JavaScript.

## Upgrading to 3.0
[Guide](https://moment.github.io/luxon/#upgrading)
## Features

@@ -20,11 +24,11 @@ * DateTime, Duration, and Interval types.

[Download/install instructions](https://moment.github.io/luxon/docs/manual/install.html)
[Download/install instructions](https://moment.github.io/luxon/#/install)
## Documentation
* [General documentation][doc-url]
* [API docs](https://moment.github.io/luxon/docs/identifiers.html)
* [Quick tour](https://moment.github.io/luxon/docs/manual/tour.html)
* [For Moment users](https://moment.github.io/luxon/docs/manual/moment.html)
* [Why does Luxon exist?](https://moment.github.io/luxon/docs/manual/why.html)
* [General documentation](https://moment.github.io/luxon/#/?id=luxon)
* [API docs](https://moment.github.io/luxon/api-docs/index.html)
* [Quick tour](https://moment.github.io/luxon/#/tour)
* [For Moment users](https://moment.github.io/luxon/#/moment)
* [Why does Luxon exist?](https://moment.github.io/luxon/#/why)
* [A quick demo](https://moment.github.io/luxon/demo/global.html)

@@ -34,11 +38,11 @@

See [contributing](contributing.md).
See [contributing](CONTRIBUTING.md).
![Phasers to stun][phasers-image]
[license-image]: http://img.shields.io/badge/license-MIT-blue.svg
[license]: license.md
[license-image]: https://img.shields.io/badge/license-MIT-blue.svg
[license]: LICENSE.md
[travis-url]: http://travis-ci.org/moment/luxon
[travis-image]: https://api.travis-ci.org/moment/luxon.svg?branch=master
[github-action-image]: https://github.com/moment/luxon/actions/workflows/test.yml/badge.svg
[github-action-url]: https://github.com/moment/luxon/actions/workflows/test.yml

@@ -48,11 +52,8 @@ [npm-url]: https://npmjs.org/package/luxon

[doc-url]: https://moment.github.io/luxon/docs/
[doc-coverage-image]: https://moment.github.io/luxon/docs/badge.svg
[test-coverage-url]: https://codecov.io/gh/moment/luxon
[test-coverage-image]: https://codecov.io/gh/moment/luxon/branch/master/graph/badge.svg
[contributing-url]: https://moment.github.io/luxon/docs/manual/contributing.html
[contributing-url]: https://github.com/moment/luxon/blob/master/CONTRIBUTING.md
[contributing-image]: https://img.shields.io/badge/PRs-welcome-brightgreen.svg
[phasers-image]: https://img.shields.io/badge/phasers-stun-brightgreen.svg

@@ -12,5 +12,6 @@ import { InvalidArgumentError, InvalidDurationError, InvalidUnitError } from "./errors.js";

normalizeObject,
roundTo
roundTo,
} from "./impl/util.js";
import Settings from "./settings.js";
import DateTime from "./datetime.js";

@@ -20,3 +21,3 @@ const INVALID = "Invalid Duration";

// unit conversion constants
const lowOrderMatrix = {
export const lowOrderMatrix = {
weeks: {

@@ -27,3 +28,3 @@ days: 7,

seconds: 7 * 24 * 60 * 60,
milliseconds: 7 * 24 * 60 * 60 * 1000
milliseconds: 7 * 24 * 60 * 60 * 1000,
},

@@ -34,74 +35,71 @@ days: {

seconds: 24 * 60 * 60,
milliseconds: 24 * 60 * 60 * 1000
milliseconds: 24 * 60 * 60 * 1000,
},
hours: { minutes: 60, seconds: 60 * 60, milliseconds: 60 * 60 * 1000 },
minutes: { seconds: 60, milliseconds: 60 * 1000 },
seconds: { milliseconds: 1000 }
seconds: { milliseconds: 1000 },
},
casualMatrix = Object.assign(
{
years: {
quarters: 4,
months: 12,
weeks: 52,
days: 365,
hours: 365 * 24,
minutes: 365 * 24 * 60,
seconds: 365 * 24 * 60 * 60,
milliseconds: 365 * 24 * 60 * 60 * 1000
},
quarters: {
months: 3,
weeks: 13,
days: 91,
hours: 91 * 24,
minutes: 91 * 24 * 60,
seconds: 91 * 24 * 60 * 60,
milliseconds: 91 * 24 * 60 * 60 * 1000
},
months: {
weeks: 4,
days: 30,
hours: 30 * 24,
minutes: 30 * 24 * 60,
seconds: 30 * 24 * 60 * 60,
milliseconds: 30 * 24 * 60 * 60 * 1000
}
casualMatrix = {
years: {
quarters: 4,
months: 12,
weeks: 52,
days: 365,
hours: 365 * 24,
minutes: 365 * 24 * 60,
seconds: 365 * 24 * 60 * 60,
milliseconds: 365 * 24 * 60 * 60 * 1000,
},
lowOrderMatrix
),
quarters: {
months: 3,
weeks: 13,
days: 91,
hours: 91 * 24,
minutes: 91 * 24 * 60,
seconds: 91 * 24 * 60 * 60,
milliseconds: 91 * 24 * 60 * 60 * 1000,
},
months: {
weeks: 4,
days: 30,
hours: 30 * 24,
minutes: 30 * 24 * 60,
seconds: 30 * 24 * 60 * 60,
milliseconds: 30 * 24 * 60 * 60 * 1000,
},
...lowOrderMatrix,
},
daysInYearAccurate = 146097.0 / 400,
daysInMonthAccurate = 146097.0 / 4800,
accurateMatrix = Object.assign(
{
years: {
quarters: 4,
months: 12,
weeks: daysInYearAccurate / 7,
days: daysInYearAccurate,
hours: daysInYearAccurate * 24,
minutes: daysInYearAccurate * 24 * 60,
seconds: daysInYearAccurate * 24 * 60 * 60,
milliseconds: daysInYearAccurate * 24 * 60 * 60 * 1000
},
quarters: {
months: 3,
weeks: daysInYearAccurate / 28,
days: daysInYearAccurate / 4,
hours: (daysInYearAccurate * 24) / 4,
minutes: (daysInYearAccurate * 24 * 60) / 4,
seconds: (daysInYearAccurate * 24 * 60 * 60) / 4,
milliseconds: (daysInYearAccurate * 24 * 60 * 60 * 1000) / 4
},
months: {
weeks: daysInMonthAccurate / 7,
days: daysInMonthAccurate,
hours: daysInMonthAccurate * 24,
minutes: daysInMonthAccurate * 24 * 60,
seconds: daysInMonthAccurate * 24 * 60 * 60,
milliseconds: daysInMonthAccurate * 24 * 60 * 60 * 1000
}
accurateMatrix = {
years: {
quarters: 4,
months: 12,
weeks: daysInYearAccurate / 7,
days: daysInYearAccurate,
hours: daysInYearAccurate * 24,
minutes: daysInYearAccurate * 24 * 60,
seconds: daysInYearAccurate * 24 * 60 * 60,
milliseconds: daysInYearAccurate * 24 * 60 * 60 * 1000,
},
lowOrderMatrix
);
quarters: {
months: 3,
weeks: daysInYearAccurate / 28,
days: daysInYearAccurate / 4,
hours: (daysInYearAccurate * 24) / 4,
minutes: (daysInYearAccurate * 24 * 60) / 4,
seconds: (daysInYearAccurate * 24 * 60 * 60) / 4,
milliseconds: (daysInYearAccurate * 24 * 60 * 60 * 1000) / 4,
},
months: {
weeks: daysInMonthAccurate / 7,
days: daysInMonthAccurate,
hours: daysInMonthAccurate * 24,
minutes: daysInMonthAccurate * 24 * 60,
seconds: daysInMonthAccurate * 24 * 60 * 60,
milliseconds: daysInMonthAccurate * 24 * 60 * 60 * 1000,
},
...lowOrderMatrix,
};

@@ -118,3 +116,3 @@ // units ordered by size

"seconds",
"milliseconds"
"milliseconds",
];

@@ -128,5 +126,6 @@

const conf = {
values: clear ? alts.values : Object.assign({}, dur.values, alts.values || {}),
values: clear ? alts.values : { ...dur.values, ...(alts.values || {}) },
loc: dur.loc.clone(alts.loc),
conversionAccuracy: alts.conversionAccuracy || dur.conversionAccuracy
conversionAccuracy: alts.conversionAccuracy || dur.conversionAccuracy,
matrix: alts.matrix || dur.matrix,
};

@@ -136,4 +135,5 @@ return new Duration(conf);

function antiTrunc(n) {
return n < 0 ? Math.floor(n) : Math.ceil(n);
// this is needed since in some test cases it would return 0.9999999999999999 instead of 1
function removePrecisionIssue(a) {
return Math.trunc(a * 1e3) / 1e3;
}

@@ -145,8 +145,6 @@

raw = fromMap[fromUnit] / conv,
sameSign = Math.sign(raw) === Math.sign(toMap[toUnit]),
// ok, so this is wild, but see the matrix in the tests
added =
!sameSign && toMap[toUnit] !== 0 && Math.abs(raw) <= 1 ? antiTrunc(raw) : Math.trunc(raw);
toMap[toUnit] += added;
fromMap[fromUnit] -= added * conv;
added = Math.floor(raw);
toMap[toUnit] = removePrecisionIssue(toMap[toUnit] + added);
fromMap[fromUnit] = removePrecisionIssue(fromMap[fromUnit] - added * conv);
}

@@ -168,4 +166,15 @@

// Remove all properties with a value of 0 from an object
function removeZeroes(vals) {
const newVals = {};
for (const [key, value] of Object.entries(vals)) {
if (value !== 0) {
newVals[key] = value;
}
}
return newVals;
}
/**
* A Duration object represents a period of time, like "2 months" or "1 day, 1 hour". Conceptually, it's just a map of units to their quantities, accompanied by some additional configuration and methods for creating, parsing, interrogating, transforming, and formatting them. They can be used on their own or in conjunction with other Luxon types; for example, you can use {@link DateTime.plus} to add a Duration object to a DateTime, producing another DateTime.
* A Duration object represents a period of time, like "2 months" or "1 day, 1 hour". Conceptually, it's just a map of units to their quantities, accompanied by some additional configuration and methods for creating, parsing, interrogating, transforming, and formatting them. They can be used on their own or in conjunction with other Luxon types; for example, you can use {@link DateTime#plus} to add a Duration object to a DateTime, producing another DateTime.
*

@@ -175,6 +184,6 @@ * 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.
* * **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}
* * **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}
*

@@ -189,2 +198,8 @@ * There's are more methods documented below. In addition, for more information on subtler topics like internationalization and validity, see the external documentation.

const accurate = config.conversionAccuracy === "longterm" || false;
let matrix = accurate ? accurateMatrix : casualMatrix;
if (config.matrix) {
matrix = config.matrix;
}
/**

@@ -209,3 +224,3 @@ * @access private

*/
this.matrix = accurate ? accurateMatrix : casualMatrix;
this.matrix = matrix;
/**

@@ -227,3 +242,3 @@ * @access private

static fromMillis(count, opts) {
return Duration.fromObject(Object.assign({ milliseconds: count }, opts));
return Duration.fromObject({ milliseconds: count }, opts);
}

@@ -244,8 +259,10 @@

* @param {number} obj.milliseconds
* @param {string} [obj.locale='en-US'] - the locale to use
* @param {string} obj.numberingSystem - the numbering system to use
* @param {string} [obj.conversionAccuracy='casual'] - the conversion system to use
* @param {Object} [opts=[]] - options for creating this Duration
* @param {string} [opts.locale='en-US'] - the locale to use
* @param {string} opts.numberingSystem - the numbering system to use
* @param {string} [opts.conversionAccuracy='casual'] - the preset conversion system to use
* @param {string} [opts.matrix=Object] - the custom conversion system to use
* @return {Duration}
*/
static fromObject(obj) {
static fromObject(obj, opts = {}) {
if (obj == null || typeof obj !== "object") {

@@ -258,11 +275,8 @@ throw new InvalidArgumentError(

}
return new Duration({
values: normalizeObject(obj, Duration.normalizeUnit, [
"locale",
"numberingSystem",
"conversionAccuracy",
"zone" // a bit of debt; it's super inconvenient internally not to be able to blindly pass this
]),
loc: Locale.fromObject(obj),
conversionAccuracy: obj.conversionAccuracy
values: normalizeObject(obj, Duration.normalizeUnit),
loc: Locale.fromObject(opts),
conversionAccuracy: opts.conversionAccuracy,
matrix: opts.matrix,
});

@@ -272,2 +286,26 @@ }

/**
* Create a Duration from DurationLike.
*
* @param {Object | number | Duration} durationLike
* One of:
* - object with keys like 'years' and 'hours'.
* - number representing milliseconds
* - Duration instance
* @return {Duration}
*/
static fromDurationLike(durationLike) {
if (isNumber(durationLike)) {
return Duration.fromMillis(durationLike);
} else if (Duration.isDuration(durationLike)) {
return durationLike;
} else if (typeof durationLike === "object") {
return Duration.fromObject(durationLike);
} else {
throw new InvalidArgumentError(
`Unknown duration argument ${durationLike} of type ${typeof durationLike}`
);
}
}
/**
* Create a Duration from an ISO 8601 duration string.

@@ -278,3 +316,4 @@ * @param {string} text - text to parse

* @param {string} opts.numberingSystem - the numbering system to use
* @param {string} [opts.conversionAccuracy='casual'] - the conversion system to use
* @param {string} [opts.conversionAccuracy='casual'] - the preset conversion system to use
* @param {string} [opts.matrix=Object] - the preset conversion system to use
* @see https://en.wikipedia.org/wiki/ISO_8601#Durations

@@ -289,4 +328,3 @@ * @example Duration.fromISO('P3Y6M1W4DT12H30M5S').toObject() //=> { years: 3, months: 6, weeks: 1, days: 4, hours: 12, minutes: 30, seconds: 5 }

if (parsed) {
const obj = Object.assign(parsed, opts);
return Duration.fromObject(obj);
return Duration.fromObject(parsed, opts);
} else {

@@ -303,3 +341,4 @@ return Duration.invalid("unparsable", `the input "${text}" can't be parsed as ISO 8601`);

* @param {string} opts.numberingSystem - the numbering system to use
* @param {string} [opts.conversionAccuracy='casual'] - the conversion system to use
* @param {string} [opts.conversionAccuracy='casual'] - the preset conversion system to use
* @param {string} [opts.matrix=Object] - the conversion system to use
* @see https://en.wikipedia.org/wiki/ISO_8601#Times

@@ -316,4 +355,3 @@ * @example Duration.fromISOTime('11:22:33.444').toObject() //=> { hours: 11, minutes: 22, seconds: 33, milliseconds: 444 }

if (parsed) {
const obj = Object.assign(parsed, opts);
return Duration.fromObject(obj);
return Duration.fromObject(parsed, opts);
} else {

@@ -366,3 +404,3 @@ return Duration.invalid("unparsable", `the input "${text}" can't be parsed as ISO 8601`);

millisecond: "milliseconds",
milliseconds: "milliseconds"
milliseconds: "milliseconds",
}[unit ? unit.toLowerCase() : unit];

@@ -408,2 +446,3 @@

* * `d` for days
* * `w` for weeks
* * `M` for months

@@ -413,3 +452,4 @@ * * `y` for years

* * Add padding by repeating the token, e.g. "yy" pads the years to two digits, "hhhh" pads the hours out to four digits
* * 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.
* * 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

@@ -425,5 +465,6 @@ * @param {Object} opts - options

// reverse-compat since 1.2; we always round down now, never up, and we do it by default
const fmtOpts = Object.assign({}, opts, {
floor: opts.round !== false && opts.floor !== false
});
const fmtOpts = {
...opts,
floor: opts.round !== false && opts.floor !== false,
};
return this.isValid

@@ -435,19 +476,40 @@ ? Formatter.create(this.loc, fmtOpts).formatDurationFromString(this, fmt)

/**
* Returns a string representation of a Duration with all units included.
* To modify its behavior use the `listStyle` and any Intl.NumberFormat option, though `unitDisplay` is especially relevant.
* @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/NumberFormat
* @param opts - On option object to override the formatting. Accepts the same keys as the options parameter of the native `Int.NumberFormat` constructor, as well as `listStyle`.
* @example
* ```js
* var dur = Duration.fromObject({ days: 1, hours: 5, minutes: 6 })
* dur.toHuman() //=> '1 day, 5 hours, 6 minutes'
* dur.toHuman({ listStyle: "long" }) //=> '1 day, 5 hours, and 6 minutes'
* dur.toHuman({ unitDisplay: "short" }) //=> '1 day, 5 hr, 6 min'
* ```
*/
toHuman(opts = {}) {
const l = orderedUnits
.map((unit) => {
const val = this.values[unit];
if (isUndefined(val)) {
return null;
}
return this.loc
.numberFormatter({ style: "unit", unitDisplay: "long", ...opts, unit: unit.slice(0, -1) })
.format(val);
})
.filter((n) => n);
return this.loc
.listFormatter({ type: "conjunction", style: opts.listStyle || "narrow", ...opts })
.format(l);
}
/**
* Returns a JavaScript object with this Duration's values.
* @param opts - options for generating the object
* @param {boolean} [opts.includeConfig=false] - include configuration attributes in the output
* @example Duration.fromObject({ years: 1, days: 6, seconds: 2 }).toObject() //=> { years: 1, days: 6, seconds: 2 }
* @return {Object}
*/
toObject(opts = {}) {
toObject() {
if (!this.isValid) return {};
const base = Object.assign({}, this.values);
if (opts.includeConfig) {
base.conversionAccuracy = this.conversionAccuracy;
base.numberingSystem = this.loc.numberingSystem;
base.locale = this.loc.locale;
}
return base;
return { ...this.values };
}

@@ -508,30 +570,13 @@

opts = Object.assign(
{
suppressMilliseconds: false,
suppressSeconds: false,
includePrefix: false,
format: "extended"
},
opts
);
opts = {
suppressMilliseconds: false,
suppressSeconds: false,
includePrefix: false,
format: "extended",
...opts,
includeOffset: false,
};
const value = this.shiftTo("hours", "minutes", "seconds", "milliseconds");
let fmt = opts.format === "basic" ? "hhmm" : "hh:mm";
if (!opts.suppressSeconds || value.seconds !== 0 || value.milliseconds !== 0) {
fmt += opts.format === "basic" ? "ss" : ":ss";
if (!opts.suppressMilliseconds || value.milliseconds !== 0) {
fmt += ".SSS";
}
}
let str = value.toFormat(fmt);
if (opts.includePrefix) {
str = "T" + str;
}
return str;
const dateTime = DateTime.fromMillis(millis, { zone: "UTC" });
return dateTime.toISOTime(opts);
}

@@ -560,3 +605,9 @@

toMillis() {
return this.as("milliseconds");
let sum = this.values.milliseconds ?? 0;
for (let unit of reverseUnits.slice(1)) {
if (this.values?.[unit]) {
sum += this.values[unit] * this.matrix[unit]["milliseconds"];
}
}
return sum;
}

@@ -580,3 +631,3 @@

const dur = friendlyDuration(duration),
const dur = Duration.fromDurationLike(duration),
result = {};

@@ -601,3 +652,3 @@

const dur = friendlyDuration(duration);
const dur = Duration.fromDurationLike(duration);
return this.plus(dur.negate());

@@ -609,4 +660,4 @@ }

* @param {function} fn - The function to apply to each unit. Arity is 1 or 2: the value of the unit and, optionally, the unit name. Must return a number.
* @example Duration.fromObject({ hours: 1, minutes: 30 }).mapUnit(x => x * 2) //=> { hours: 2, minutes: 60 }
* @example Duration.fromObject({ hours: 1, minutes: 30 }).mapUnit((x, u) => u === "hour" ? x * 2 : x) //=> { hours: 2, minutes: 30 }
* @example Duration.fromObject({ hours: 1, minutes: 30 }).mapUnits(x => x * 2) //=> { hours: 2, minutes: 60 }
* @example Duration.fromObject({ hours: 1, minutes: 30 }).mapUnits((x, u) => u === "hours" ? x * 2 : x) //=> { hours: 2, minutes: 30 }
* @return {Duration}

@@ -645,3 +696,3 @@ */

const mixed = Object.assign(this.values, normalizeObject(values, Duration.normalizeUnit, []));
const mixed = { ...this.values, ...normalizeObject(values, Duration.normalizeUnit) };
return clone(this, { values: mixed });

@@ -655,10 +706,5 @@ }

*/
reconfigure({ locale, numberingSystem, conversionAccuracy } = {}) {
const loc = this.loc.clone({ locale, numberingSystem }),
opts = { loc };
if (conversionAccuracy) {
opts.conversionAccuracy = conversionAccuracy;
}
reconfigure({ locale, numberingSystem, conversionAccuracy, matrix } = {}) {
const loc = this.loc.clone({ locale, numberingSystem });
const opts = { loc, matrix, conversionAccuracy };
return clone(this, opts);

@@ -688,3 +734,17 @@ }

const vals = this.toObject();
normalizeValues(this.matrix, vals);
if (this.valueOf() >= 0) {
normalizeValues(this.matrix, vals);
return clone(this, { values: vals }, true);
}
return this.negate().normalize().negate();
}
/**
* Rescale units to its largest representation
* @example Duration.fromObject({ milliseconds: 90000 }).rescale().toObject() //=> { minutes: 1, seconds: 30 }
* @return {Duration}
*/
rescale() {
if (!this.isValid) return this;
const vals = removeZeroes(this.normalize().shiftToAll().toObject());
return clone(this, { values: vals }, true);

@@ -705,3 +765,3 @@ }

units = units.map(u => Duration.normalizeUnit(u));
units = units.map((u) => Duration.normalizeUnit(u));

@@ -732,3 +792,3 @@ const built = {},

built[k] = i;
accumulated[k] = own - i; // we'd like to absorb these fractions in another unit
accumulated[k] = (own * 1000 - i * 1000) / 1000;

@@ -760,2 +820,21 @@ // plus anything further down the chain that should be rolled up in to this

/**
* Shift this Duration to all available units.
* Same as shiftTo("years", "months", "weeks", "days", "hours", "minutes", "seconds", "milliseconds")
* @return {Duration}
*/
shiftToAll() {
if (!this.isValid) return this;
return this.shiftTo(
"years",
"months",
"weeks",
"days",
"hours",
"minutes",
"seconds",
"milliseconds"
);
}
/**
* Return the negative of this Duration.

@@ -769,3 +848,3 @@ * @example Duration.fromObject({ hours: 1, seconds: 30 }).negate().toObject() //=> { hours: -1, seconds: -30 }

for (const k of Object.keys(this.values)) {
negated[k] = -this.values[k];
negated[k] = this.values[k] === 0 ? 0 : -this.values[k];
}

@@ -901,18 +980,1 @@ return clone(this, { values: negated }, true);

}
/**
* @private
*/
export function friendlyDuration(durationish) {
if (isNumber(durationish)) {
return Duration.fromMillis(durationish);
} else if (Duration.isDuration(durationish)) {
return durationish;
} else if (typeof durationish === "object") {
return Duration.fromObject(durationish);
} else {
throw new InvalidArgumentError(
`Unknown duration argument ${durationish} of type ${typeof durationish}`
);
}
}

@@ -8,3 +8,3 @@ import {

weeksInWeekYear,
isInteger
isInteger,
} from "./util.js";

@@ -24,3 +24,10 @@ import Invalid from "./invalid.js";

function dayOfWeek(year, month, day) {
const js = new Date(Date.UTC(year, month - 1, day)).getUTCDay();
const d = new Date(Date.UTC(year, month - 1, day));
if (year < 100 && year >= 0) {
d.setUTCFullYear(d.getUTCFullYear() - 1900);
}
const js = d.getUTCDay();
return js === 0 ? 7 : js;

@@ -35,3 +42,3 @@ }

const table = isLeapYear(year) ? leapLadder : nonLeapLadder,
month0 = table.findIndex(i => i < ordinal),
month0 = table.findIndex((i) => i < ordinal),
day = ordinal - table[month0];

@@ -63,3 +70,3 @@ return { month: month0 + 1, day };

return Object.assign({ weekYear, weekNumber, weekday }, timeObject(gregObj));
return { weekYear, weekNumber, weekday, ...timeObject(gregObj) };
}

@@ -86,18 +93,15 @@

const { month, day } = uncomputeOrdinal(year, ordinal);
return Object.assign({ year, month, day }, timeObject(weekData));
return { year, month, day, ...timeObject(weekData) };
}
export function gregorianToOrdinal(gregData) {
const { year, month, day } = gregData,
ordinal = computeOrdinal(year, month, day);
return Object.assign({ year, ordinal }, timeObject(gregData));
const { year, month, day } = gregData;
const ordinal = computeOrdinal(year, month, day);
return { year, ordinal, ...timeObject(gregData) };
}
export function ordinalToGregorian(ordinalData) {
const { year, ordinal } = ordinalData,
{ month, day } = uncomputeOrdinal(year, ordinal);
return Object.assign({ year, month, day }, timeObject(ordinalData));
const { year, ordinal } = ordinalData;
const { month, day } = uncomputeOrdinal(year, ordinal);
return { year, month, day, ...timeObject(ordinalData) };
}

@@ -104,0 +108,0 @@

import Duration from "../duration.js";
function dayDiff(earlier, later) {
const utcDayStart = dt =>
dt
.toUTC(0, { keepLocalTime: true })
.startOf("day")
.valueOf(),
const utcDayStart = (dt) => dt.toUTC(0, { keepLocalTime: true }).startOf("day").valueOf(),
ms = utcDayStart(later) - utcDayStart(earlier);

@@ -16,3 +12,3 @@ return Math.floor(Duration.fromMillis(ms).as("days"));

["years", (a, b) => b.year - a.year],
["quarters", (a, b) => b.quarter - a.quarter],
["quarters", (a, b) => b.quarter - a.quarter + (b.year - a.year) * 4],
["months", (a, b) => b.month - a.month + (b.year - a.year) * 12],

@@ -24,10 +20,19 @@ [

return (days - (days % 7)) / 7;
}
},
],
["days", dayDiff]
["days", dayDiff],
];
const results = {};
const earlier = cursor;
let lowestOrder, highWater;
/* This loop tries to diff using larger units first.
If we overshoot, we backtrack and try the next smaller unit.
"cursor" starts out at the earlier timestamp and moves closer and closer to "later"
as we use smaller and smaller units.
highWater keeps track of where we would be if we added one more of the smallest unit,
this is used later to potentially convert any difference smaller than the smallest higher order unit
into a fraction of that smallest higher order unit
*/
for (const [unit, differ] of differs) {

@@ -37,13 +42,23 @@ if (units.indexOf(unit) >= 0) {

let delta = differ(cursor, later);
highWater = cursor.plus({ [unit]: delta });
results[unit] = differ(cursor, later);
highWater = earlier.plus(results);
if (highWater > later) {
cursor = cursor.plus({ [unit]: delta - 1 });
delta -= 1;
// we overshot the end point, backtrack cursor by 1
results[unit]--;
cursor = earlier.plus(results);
// if we are still overshooting now, we need to backtrack again
// this happens in certain situations when diffing times in different zones,
// because this calculation ignores time zones
if (cursor > later) {
// keep the "overshot by 1" around as highWater
highWater = cursor;
// backtrack cursor by 1
results[unit]--;
cursor = earlier.plus(results);
}
} else {
cursor = highWater;
}
results[unit] = delta;
}

@@ -55,3 +70,3 @@ }

export default function(earlier, later, units, opts) {
export default function (earlier, later, units, opts) {
let [cursor, results, highWater, lowestOrder] = highOrderDiffs(earlier, later, units);

@@ -62,3 +77,3 @@

const lowerOrderUnits = units.filter(
u => ["hours", "minutes", "seconds", "milliseconds"].indexOf(u) >= 0
(u) => ["hours", "minutes", "seconds", "milliseconds"].indexOf(u) >= 0
);

@@ -76,3 +91,3 @@

const duration = Duration.fromObject(Object.assign(results, opts));
const duration = Duration.fromObject(results, opts);

@@ -79,0 +94,0 @@ if (lowerOrderUnits.length > 0) {

@@ -22,3 +22,3 @@ const numberingSystems = {

tibt: "[\u0F20-\u0F29]",
latn: "\\d"
latn: "\\d",
};

@@ -45,6 +45,5 @@

thai: [3664, 3673],
tibt: [3872, 3881]
tibt: [3872, 3881],
};
// eslint-disable-next-line
const hanidecChars = numberingSystems.hanidec.replace(/[\[|\]]/g, "").split("");

@@ -51,0 +50,0 @@

@@ -24,3 +24,3 @@ import * as Formats from "./formats.js";

"November",
"December"
"December",
];

@@ -40,3 +40,3 @@

"Nov",
"Dec"
"Dec",
];

@@ -70,3 +70,3 @@

"Saturday",
"Sunday"
"Sunday",
];

@@ -139,3 +139,3 @@

minutes: ["minute", "min."],
seconds: ["second", "sec."]
seconds: ["second", "sec."],
};

@@ -167,4 +167,4 @@

: singular
? units[unit][0]
: unit;
? units[unit][0]
: unit;
return isInPast ? `${fmtValue} ${fmtUnit} ago` : `in ${fmtValue} ${fmtUnit}`;

@@ -186,3 +186,3 @@ }

"timeZoneName",
"hour12"
"hourCycle",
]),

@@ -189,0 +189,0 @@ key = stringify(filtered),

@@ -12,3 +12,3 @@ /**

month: n,
day: n
day: n,
};

@@ -19,3 +19,3 @@

month: s,
day: n
day: n,
};

@@ -27,3 +27,3 @@

day: n,
weekday: s
weekday: s,
};

@@ -34,3 +34,3 @@

month: l,
day: n
day: n,
};

@@ -42,3 +42,3 @@

day: n,
weekday: l
weekday: l,
};

@@ -48,3 +48,3 @@

hour: n,
minute: n
minute: n,
};

@@ -55,3 +55,3 @@

minute: n,
second: n
second: n,
};

@@ -63,3 +63,3 @@

second: n,
timeZoneName: s
timeZoneName: s,
};

@@ -71,3 +71,3 @@

second: n,
timeZoneName: l
timeZoneName: l,
};

@@ -78,8 +78,5 @@

minute: n,
hour12: false
hourCycle: "h23",
};
/**
* {@link toLocaleString}; format like '09:30:23', always 24-hour.
*/
export const TIME_24_WITH_SECONDS = {

@@ -89,8 +86,5 @@ hour: n,

second: n,
hour12: false
hourCycle: "h23",
};
/**
* {@link toLocaleString}; format like '09:30:23 EDT', always 24-hour.
*/
export const TIME_24_WITH_SHORT_OFFSET = {

@@ -100,9 +94,6 @@ hour: n,

second: n,
hour12: false,
timeZoneName: s
hourCycle: "h23",
timeZoneName: s,
};
/**
* {@link toLocaleString}; format like '09:30:23 Eastern Daylight Time', always 24-hour.
*/
export const TIME_24_WITH_LONG_OFFSET = {

@@ -112,9 +103,6 @@ hour: n,

second: n,
hour12: false,
timeZoneName: l
hourCycle: "h23",
timeZoneName: l,
};
/**
* {@link toLocaleString}; format like '10/14/1983, 9:30 AM'. Only 12-hour if the locale is.
*/
export const DATETIME_SHORT = {

@@ -125,8 +113,5 @@ year: n,

hour: n,
minute: n
minute: n,
};
/**
* {@link toLocaleString}; format like '10/14/1983, 9:30:33 AM'. Only 12-hour if the locale is.
*/
export const DATETIME_SHORT_WITH_SECONDS = {

@@ -138,3 +123,3 @@ year: n,

minute: n,
second: n
second: n,
};

@@ -147,3 +132,3 @@

hour: n,
minute: n
minute: n,
};

@@ -157,3 +142,3 @@

minute: n,
second: n
second: n,
};

@@ -167,3 +152,3 @@

hour: n,
minute: n
minute: n,
};

@@ -177,3 +162,3 @@

minute: n,
timeZoneName: s
timeZoneName: s,
};

@@ -188,3 +173,3 @@

second: n,
timeZoneName: s
timeZoneName: s,
};

@@ -199,3 +184,3 @@

minute: n,
timeZoneName: l
timeZoneName: l,
};

@@ -211,3 +196,3 @@

second: n,
timeZoneName: l
timeZoneName: l,
};
import * as English from "./english.js";
import * as Formats from "./formats.js";
import { hasFormatToParts, padStart } from "./util.js";
import { padStart } from "./util.js";

@@ -37,3 +37,3 @@ function stringifyTokens(splits, tokenToString) {

FFF: Formats.DATETIME_FULL_WITH_SECONDS,
FFFF: Formats.DATETIME_HUGE_WITH_SECONDS
FFFF: Formats.DATETIME_HUGE_WITH_SECONDS,
};

@@ -51,2 +51,5 @@

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,

@@ -60,3 +63,3 @@ currentFull = "",

if (currentFull.length > 0) {
splits.push({ literal: bracketed, val: currentFull });
splits.push({ literal: bracketed || /^\s+$/.test(currentFull), val: currentFull });
}

@@ -72,3 +75,3 @@ current = null;

if (currentFull.length > 0) {
splits.push({ literal: false, val: currentFull });
splits.push({ literal: /^\s+$/.test(currentFull), val: currentFull });
}

@@ -81,3 +84,3 @@ currentFull = c;

if (currentFull.length > 0) {
splits.push({ literal: bracketed, val: currentFull });
splits.push({ literal: bracketed || /^\s+$/.test(currentFull), val: currentFull });
}

@@ -102,21 +105,27 @@

}
const df = this.systemLoc.dtFormatter(dt, Object.assign({}, this.opts, opts));
const df = this.systemLoc.dtFormatter(dt, { ...this.opts, ...opts });
return df.format();
}
formatDateTime(dt, opts = {}) {
const df = this.loc.dtFormatter(dt, Object.assign({}, this.opts, opts));
return df.format();
dtFormatter(dt, opts = {}) {
return this.loc.dtFormatter(dt, { ...this.opts, ...opts });
}
formatDateTimeParts(dt, opts = {}) {
const df = this.loc.dtFormatter(dt, Object.assign({}, this.opts, opts));
return df.formatToParts();
formatDateTime(dt, opts) {
return this.dtFormatter(dt, opts).format();
}
resolvedOptions(dt, opts = {}) {
const df = this.loc.dtFormatter(dt, Object.assign({}, this.opts, opts));
return df.resolvedOptions();
formatDateTimeParts(dt, opts) {
return this.dtFormatter(dt, opts).formatToParts();
}
formatInterval(interval, opts) {
const df = this.dtFormatter(interval.start, opts);
return df.dtf.formatRange(interval.start.toJSDate(), interval.end.toJSDate());
}
resolvedOptions(dt, opts) {
return this.dtFormatter(dt, opts).resolvedOptions();
}
num(n, p = 0) {

@@ -128,3 +137,3 @@ // we get some perf out of doing this here, annoyingly

const opts = Object.assign({}, this.opts);
const opts = { ...this.opts };

@@ -140,6 +149,5 @@ if (p > 0) {

const knownEnglish = this.loc.listingMode() === "en",
useDateTimeFormatter =
this.loc.outputCalendar && this.loc.outputCalendar !== "gregory" && hasFormatToParts(),
useDateTimeFormatter = this.loc.outputCalendar && this.loc.outputCalendar !== "gregory",
string = (opts, extract) => this.loc.extract(dt, opts, extract),
formatOffset = opts => {
formatOffset = (opts) => {
if (dt.isOffsetFixed && dt.offset === 0 && opts.allowZ) {

@@ -154,3 +162,3 @@ return "Z";

? English.meridiemForDateTime(dt)
: string({ hour: "numeric", hour12: true }, "dayperiod"),
: string({ hour: "numeric", hourCycle: "h12" }, "dayperiod"),
month = (length, standalone) =>

@@ -167,3 +175,3 @@ knownEnglish

),
maybeMacro = token => {
maybeMacro = (token) => {
const formatOpts = Formatter.macroTokenToFormatOpts(token);

@@ -176,6 +184,6 @@ if (formatOpts) {

},
era = length =>
era = (length) =>
knownEnglish ? English.eraForDateTime(dt, length) : string({ era: length }, "era"),
tokenToString = token => {
// Where possible: http://cldr.unicode.org/translation/date-time-1/date-time#TOC-Standalone-vs.-Format-Styles
tokenToString = (token) => {
// Where possible: https://cldr.unicode.org/translation/date-time/date-time-symbols
switch (token) {

@@ -194,2 +202,7 @@ // ms

return this.num(dt.second, 2);
// fractional seconds
case "uu":
return this.num(Math.floor(dt.millisecond / 10), 2);
case "uuu":
return this.num(Math.floor(dt.millisecond / 100));
// minutes

@@ -362,3 +375,3 @@ case "m":

formatDurationFromString(dur, fmt) {
const tokenToField = token => {
const tokenToField = (token) => {
switch (token[0]) {

@@ -375,2 +388,4 @@ case "S":

return "day";
case "w":
return "week";
case "M":

@@ -384,3 +399,3 @@ return "month";

},
tokenToString = lildur => token => {
tokenToString = (lildur) => (token) => {
const mapped = tokenToField(token);

@@ -398,5 +413,5 @@ if (mapped) {

),
collapsed = dur.shiftTo(...realTokens.map(tokenToField).filter(t => t));
collapsed = dur.shiftTo(...realTokens.map(tokenToField).filter((t) => t));
return stringifyTokens(tokens, tokenToString(collapsed));
}
}

@@ -1,8 +0,20 @@

import { hasFormatToParts, hasIntl, padStart, roundTo, hasRelative } from "./util.js";
import { padStart, roundTo, hasRelative, formatOffset } from "./util.js";
import * as English from "./english.js";
import Settings from "../settings.js";
import DateTime from "../datetime.js";
import Formatter from "./formatter.js";
import IANAZone from "../zones/IANAZone.js";
// todo - remap caching
let intlLFCache = {};
function getCachedLF(locString, opts = {}) {
const key = JSON.stringify([locString, opts]);
let dtf = intlLFCache[key];
if (!dtf) {
dtf = new Intl.ListFormat(locString, opts);
intlLFCache[key] = dtf;
}
return dtf;
}
let intlDTCache = {};

@@ -46,9 +58,4 @@ function getCachedDTF(locString, opts = {}) {

return sysLocaleCache;
} else if (hasIntl()) {
const computedSys = new Intl.DateTimeFormat().resolvedOptions().locale;
// node sometimes defaults to "und". Override that because that is dumb
sysLocaleCache = !computedSys || computedSys === "und" ? "en-US" : computedSys;
return sysLocaleCache;
} else {
sysLocaleCache = "en-US";
sysLocaleCache = new Intl.DateTimeFormat().resolvedOptions().locale;
return sysLocaleCache;

@@ -67,2 +74,10 @@ }

// private subtags and unicode subtags have ordering requirements,
// and we're not properly parsing this, so just strip out the
// private ones if they exist.
const xIndex = localeStr.indexOf("-x-");
if (xIndex !== -1) {
localeStr = localeStr.substring(0, xIndex);
}
const uIndex = localeStr.indexOf("-u-");

@@ -73,12 +88,14 @@ if (uIndex === -1) {

let options;
const smaller = localeStr.substring(0, uIndex);
let selectedStr;
try {
options = getCachedDTF(localeStr).resolvedOptions();
selectedStr = localeStr;
} catch (e) {
const smaller = localeStr.substring(0, uIndex);
options = getCachedDTF(smaller).resolvedOptions();
selectedStr = smaller;
}
const { numberingSystem, calendar } = options;
// return the smaller one so that we can append the calendar and numbering overrides to it
return [smaller, numberingSystem, calendar];
return [selectedStr, numberingSystem, calendar];
}

@@ -88,19 +105,17 @@ }

function intlConfigString(localeStr, numberingSystem, outputCalendar) {
if (hasIntl()) {
if (outputCalendar || numberingSystem) {
if (outputCalendar || numberingSystem) {
if (!localeStr.includes("-u-")) {
localeStr += "-u";
}
if (outputCalendar) {
localeStr += `-ca-${outputCalendar}`;
}
if (outputCalendar) {
localeStr += `-ca-${outputCalendar}`;
}
if (numberingSystem) {
localeStr += `-nu-${numberingSystem}`;
}
return localeStr;
} else {
return localeStr;
if (numberingSystem) {
localeStr += `-nu-${numberingSystem}`;
}
return localeStr;
} else {
return [];
return localeStr;
}

@@ -112,3 +127,3 @@ }

for (let i = 1; i <= 12; i++) {
const dt = DateTime.utc(2016, i, 1);
const dt = DateTime.utc(2009, i, 1);
ms.push(f(dt));

@@ -128,4 +143,4 @@ }

function listStuff(loc, length, defaultOK, englishFn, intlFn) {
const mode = loc.listingMode(defaultOK);
function listStuff(loc, length, englishFn, intlFn) {
const mode = loc.listingMode();

@@ -149,3 +164,3 @@ if (mode === "error") {

loc.locale.startsWith("en") ||
(hasIntl() && new Intl.DateTimeFormat(loc.intl).resolvedOptions().numberingSystem === "latn")
new Intl.DateTimeFormat(loc.intl).resolvedOptions().numberingSystem === "latn"
);

@@ -164,4 +179,6 @@ }

if (!forceSimple && hasIntl()) {
const intlOpts = { useGrouping: false };
const { padTo, floor, ...otherOpts } = opts;
if (!forceSimple || Object.keys(otherOpts).length > 0) {
const intlOpts = { useGrouping: false, ...opts };
if (opts.padTo > 0) intlOpts.minimumIntegerDigits = opts.padTo;

@@ -191,6 +208,9 @@ this.inf = getCachedINF(intl, intlOpts);

this.opts = opts;
this.hasIntl = hasIntl();
this.originalZone = undefined;
let z;
if (dt.zone.universal && this.hasIntl) {
let z = undefined;
if (this.opts.timeZone) {
// Don't apply any workarounds if a timeZone is explicitly provided in opts
this.dt = dt;
} else if (dt.zone.type === "fixed") {
// UTC-8 or Etc/UTC-8 are not part of tzdata, only Etc/GMT+8 and the like.

@@ -204,67 +224,64 @@ // That is why fixed-offset TZ is set to that unless it is:

const offsetZ = gmtOffset >= 0 ? `Etc/GMT+${gmtOffset}` : `Etc/GMT${gmtOffset}`;
const isOffsetZoneSupported = IANAZone.isValidZone(offsetZ);
if (dt.offset !== 0 && isOffsetZoneSupported) {
if (dt.offset !== 0 && IANAZone.create(offsetZ).valid) {
z = offsetZ;
this.dt = dt;
} else {
// Not all fixed-offset zones like Etc/+4:30 are present in tzdata.
// So we have to make do. Two cases:
// 1. The format options tell us to show the zone. We can't do that, so the best
// we can do is format the date in UTC.
// 2. The format options don't tell us to show the zone. Then we can adjust them
// the time and tell the formatter to show it to us in UTC, so that the time is right
// and the bad zone doesn't show up.
// Not all fixed-offset zones like Etc/+4:30 are present in tzdata so
// we manually apply the offset and substitute the zone as needed.
z = "UTC";
if (opts.timeZoneName) {
this.dt = dt;
} else {
this.dt = dt.offset === 0 ? dt : DateTime.fromMillis(dt.ts + dt.offset * 60 * 1000);
}
this.dt = dt.offset === 0 ? dt : dt.setZone("UTC").plus({ minutes: dt.offset });
this.originalZone = dt.zone;
}
} else if (dt.zone.type === "local") {
} else if (dt.zone.type === "system") {
this.dt = dt;
} else {
} else if (dt.zone.type === "iana") {
this.dt = dt;
z = dt.zone.name;
} else {
// Custom zones can have any offset / offsetName so we just manually
// apply the offset and substitute the zone as needed.
z = "UTC";
this.dt = dt.setZone("UTC").plus({ minutes: dt.offset });
this.originalZone = dt.zone;
}
if (this.hasIntl) {
const intlOpts = Object.assign({}, this.opts);
if (z) {
intlOpts.timeZone = z;
}
this.dtf = getCachedDTF(intl, intlOpts);
}
const intlOpts = { ...this.opts };
intlOpts.timeZone = intlOpts.timeZone || z;
this.dtf = getCachedDTF(intl, intlOpts);
}
format() {
if (this.hasIntl) {
return this.dtf.format(this.dt.toJSDate());
} else {
const tokenFormat = English.formatString(this.opts),
loc = Locale.create("en-US");
return Formatter.create(loc).formatDateTimeFromString(this.dt, tokenFormat);
if (this.originalZone) {
// If we have to substitute in the actual zone name, we have to use
// formatToParts so that the timezone can be replaced.
return this.formatToParts()
.map(({ value }) => value)
.join("");
}
return this.dtf.format(this.dt.toJSDate());
}
formatToParts() {
if (this.hasIntl && hasFormatToParts()) {
return this.dtf.formatToParts(this.dt.toJSDate());
} else {
// This is kind of a cop out. We actually could do this for English. However, we couldn't do it for intl strings
// and IMO it's too weird to have an uncanny valley like that
return [];
const parts = this.dtf.formatToParts(this.dt.toJSDate());
if (this.originalZone) {
return parts.map((part) => {
if (part.type === "timeZoneName") {
const offsetName = this.originalZone.offsetName(this.dt.ts, {
locale: this.dt.locale,
format: this.opts.timeZoneName,
});
return {
...part,
value: offsetName,
};
} else {
return part;
}
});
}
return parts;
}
resolvedOptions() {
if (this.hasIntl) {
return this.dtf.resolvedOptions();
} else {
return {
locale: "en-US",
numberingSystem: "latn",
outputCalendar: "gregory"
};
}
return this.dtf.resolvedOptions();
}

@@ -278,3 +295,3 @@ }

constructor(intl, isEnglish, opts) {
this.opts = Object.assign({ style: "long" }, opts);
this.opts = { style: "long", ...opts };
if (!isEnglish && hasRelative()) {

@@ -312,7 +329,7 @@ this.rtf = getCachedRTF(intl, opts);

static create(locale, numberingSystem, outputCalendar, defaultToEN = false) {
const specifiedLocale = locale || Settings.defaultLocale,
// the system locale is useful for human readable strings but annoying for parsing/formatting known formats
localeR = specifiedLocale || (defaultToEN ? "en-US" : systemLocale()),
numberingSystemR = numberingSystem || Settings.defaultNumberingSystem,
outputCalendarR = outputCalendar || Settings.defaultOutputCalendar;
const specifiedLocale = locale || Settings.defaultLocale;
// the system locale is useful for human readable strings but annoying for parsing/formatting known formats
const localeR = specifiedLocale || (defaultToEN ? "en-US" : systemLocale());
const numberingSystemR = numberingSystem || Settings.defaultNumberingSystem;
const outputCalendarR = outputCalendar || Settings.defaultOutputCalendar;
return new Locale(localeR, numberingSystemR, outputCalendarR, specifiedLocale);

@@ -357,17 +374,8 @@ }

listingMode(defaultOK = true) {
const intl = hasIntl(),
hasFTP = intl && hasFormatToParts(),
isActuallyEn = this.isEnglish(),
hasNoWeirdness =
(this.numberingSystem === null || this.numberingSystem === "latn") &&
(this.outputCalendar === null || this.outputCalendar === "gregory");
if (!hasFTP && !(isActuallyEn && hasNoWeirdness) && !defaultOK) {
return "error";
} else if (!hasFTP || (isActuallyEn && hasNoWeirdness)) {
return "en";
} else {
return "intl";
}
listingMode() {
const isActuallyEn = this.isEnglish();
const hasNoWeirdness =
(this.numberingSystem === null || this.numberingSystem === "latn") &&
(this.outputCalendar === null || this.outputCalendar === "gregory");
return isActuallyEn && hasNoWeirdness ? "en" : "intl";
}

@@ -389,15 +397,15 @@

redefaultToEN(alts = {}) {
return this.clone(Object.assign({}, alts, { defaultToEN: true }));
return this.clone({ ...alts, defaultToEN: true });
}
redefaultToSystem(alts = {}) {
return this.clone(Object.assign({}, alts, { defaultToEN: false }));
return this.clone({ ...alts, defaultToEN: false });
}
months(length, format = false, defaultOK = true) {
return listStuff(this, length, defaultOK, English.months, () => {
months(length, format = false) {
return listStuff(this, length, English.months, () => {
const intl = format ? { month: length, day: "numeric" } : { month: length },
formatStr = format ? "format" : "standalone";
if (!this.monthsCache[formatStr][length]) {
this.monthsCache[formatStr][length] = mapMonths(dt => this.extract(dt, intl, "month"));
this.monthsCache[formatStr][length] = mapMonths((dt) => this.extract(dt, intl, "month"));
}

@@ -408,4 +416,4 @@ return this.monthsCache[formatStr][length];

weekdays(length, format = false, defaultOK = true) {
return listStuff(this, length, defaultOK, English.weekdays, () => {
weekdays(length, format = false) {
return listStuff(this, length, English.weekdays, () => {
const intl = format

@@ -416,3 +424,3 @@ ? { weekday: length, year: "numeric", month: "long", day: "numeric" }

if (!this.weekdaysCache[formatStr][length]) {
this.weekdaysCache[formatStr][length] = mapWeekdays(dt =>
this.weekdaysCache[formatStr][length] = mapWeekdays((dt) =>
this.extract(dt, intl, "weekday")

@@ -425,7 +433,6 @@ );

meridiems(defaultOK = true) {
meridiems() {
return listStuff(
this,
undefined,
defaultOK,
() => English.meridiems,

@@ -436,5 +443,5 @@ () => {

if (!this.meridiemCache) {
const intl = { hour: "numeric", hour12: true };
const intl = { hour: "numeric", hourCycle: "h12" };
this.meridiemCache = [DateTime.utc(2016, 11, 13, 9), DateTime.utc(2016, 11, 13, 19)].map(
dt => this.extract(dt, intl, "dayperiod")
(dt) => this.extract(dt, intl, "dayperiod")
);

@@ -448,4 +455,4 @@ }

eras(length, defaultOK = true) {
return listStuff(this, length, defaultOK, English.eras, () => {
eras(length) {
return listStuff(this, length, English.eras, () => {
const intl = { era: length };

@@ -456,3 +463,3 @@

if (!this.eraCache[length]) {
this.eraCache[length] = [DateTime.utc(-40, 1, 1), DateTime.utc(2017, 1, 1)].map(dt =>
this.eraCache[length] = [DateTime.utc(-40, 1, 1), DateTime.utc(2017, 1, 1)].map((dt) =>
this.extract(dt, intl, "era")

@@ -469,3 +476,3 @@ );

results = df.formatToParts(),
matching = results.find(m => m.type.toLowerCase() === field);
matching = results.find((m) => m.type.toLowerCase() === field);
return matching ? matching.value : null;

@@ -488,2 +495,6 @@ }

listFormatter(opts = {}) {
return getCachedLF(this.intl, opts);
}
isEnglish() {

@@ -493,3 +504,3 @@ return (

this.locale.toLowerCase() === "en-us" ||
(hasIntl() && new Intl.DateTimeFormat(this.intl).resolvedOptions().locale.startsWith("en-us"))
new Intl.DateTimeFormat(this.intl).resolvedOptions().locale.startsWith("en-us")
);

@@ -496,0 +507,0 @@ }

@@ -6,4 +6,4 @@ import {

parseMillis,
ianaRegex,
isUndefined
isUndefined,
parseFloating,
} from "./util.js";

@@ -24,2 +24,4 @@ import * as English from "./english.js";

const ianaRegex = /[A-Za-z_+-]{1,256}(?::?\/[A-Za-z0-9_+-]{1,256}(?:\/[A-Za-z0-9_+-]{1,256})?)?/;
function combineRegexes(...regexes) {

@@ -31,3 +33,3 @@ const full = regexes.reduce((f, r) => f + r.source, "");

function combineExtractors(...extractors) {
return m =>
return (m) =>
extractors

@@ -37,3 +39,3 @@ .reduce(

const [val, zone, next] = ex(m, cursor);
return [Object.assign(mergedVals, val), mergedZone || zone, next];
return [{ ...mergedVals, ...val }, zone || mergedZone, next];
},

@@ -72,16 +74,17 @@ [{}, null, 1]

// ISO and SQL parsing
const offsetRegex = /(?:(Z)|([+-]\d\d)(?::?(\d\d))?)/,
isoTimeBaseRegex = /(\d\d)(?::?(\d\d)(?::?(\d\d)(?:[.,](\d{1,30}))?)?)?/,
isoTimeRegex = RegExp(`${isoTimeBaseRegex.source}${offsetRegex.source}?`),
isoTimeExtensionRegex = RegExp(`(?:T${isoTimeRegex.source})?`),
isoYmdRegex = /([+-]\d{6}|\d{4})(?:-?(\d\d)(?:-?(\d\d))?)?/,
isoWeekRegex = /(\d{4})-?W(\d\d)(?:-?(\d))?/,
isoOrdinalRegex = /(\d{4})-?(\d{3})/,
extractISOWeekData = simpleParse("weekYear", "weekNumber", "weekDay"),
extractISOOrdinalData = simpleParse("year", "ordinal"),
sqlYmdRegex = /(\d{4})-(\d\d)-(\d\d)/, // dumbed-down version of the ISO one
sqlTimeRegex = RegExp(
`${isoTimeBaseRegex.source} ?(?:${offsetRegex.source}|(${ianaRegex.source}))?`
),
sqlTimeExtensionRegex = RegExp(`(?: ${sqlTimeRegex.source})?`);
const offsetRegex = /(?:(Z)|([+-]\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 isoYmdRegex = /([+-]\d{6}|\d{4})(?:-?(\d\d)(?:-?(\d\d))?)?/;
const isoWeekRegex = /(\d{4})-?W(\d\d)(?:-?(\d))?/;
const isoOrdinalRegex = /(\d{4})-?(\d{3})/;
const extractISOWeekData = simpleParse("weekYear", "weekNumber", "weekDay");
const extractISOOrdinalData = simpleParse("year", "ordinal");
const sqlYmdRegex = /(\d{4})-(\d\d)-(\d\d)/; // dumbed-down version of the ISO one
const sqlTimeRegex = RegExp(
`${isoTimeBaseRegex.source} ?(?:${offsetRegex.source}|(${ianaRegex.source}))?`
);
const sqlTimeExtensionRegex = RegExp(`(?: ${sqlTimeRegex.source})?`);

@@ -97,3 +100,3 @@ function int(match, pos, fallback) {

month: int(match, cursor + 1, 1),
day: int(match, cursor + 2, 1)
day: int(match, cursor + 2, 1),
};

@@ -109,3 +112,3 @@

seconds: int(match, cursor + 2, 0),
milliseconds: parseMillis(match[cursor + 3])
milliseconds: parseMillis(match[cursor + 3]),
};

@@ -134,16 +137,8 @@

const isoDuration = /^-?P(?:(?:(-?\d{1,9})Y)?(?:(-?\d{1,9})M)?(?:(-?\d{1,9})W)?(?:(-?\d{1,9})D)?(?:T(?:(-?\d{1,9})H)?(?:(-?\d{1,9})M)?(?:(-?\d{1,20})(?:[.,](-?\d{1,9}))?S)?)?)$/;
const isoDuration =
/^-?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
] = match;
const [s, yearStr, monthStr, weekStr, dayStr, hourStr, minuteStr, secondStr, millisecondsStr] =
match;

@@ -158,11 +153,11 @@ const hasNegativePrefix = s[0] === "-";

{
years: maybeNegate(parseInteger(yearStr)),
months: maybeNegate(parseInteger(monthStr)),
weeks: maybeNegate(parseInteger(weekStr)),
days: maybeNegate(parseInteger(dayStr)),
hours: maybeNegate(parseInteger(hourStr)),
minutes: maybeNegate(parseInteger(minuteStr)),
seconds: maybeNegate(parseInteger(secondStr), secondStr === "-0"),
milliseconds: maybeNegate(parseMillis(millisecondsStr), negativeSeconds)
}
years: maybeNegate(parseFloating(yearStr)),
months: maybeNegate(parseFloating(monthStr)),
weeks: maybeNegate(parseFloating(weekStr)),
days: maybeNegate(parseFloating(dayStr)),
hours: maybeNegate(parseFloating(hourStr)),
minutes: maybeNegate(parseFloating(minuteStr)),
seconds: maybeNegate(parseFloating(secondStr), secondStr === "-0"),
milliseconds: maybeNegate(parseMillis(millisecondsStr), negativeSeconds),
},
];

@@ -183,3 +178,3 @@ }

PDT: -7 * 60,
PST: -8 * 60
PST: -8 * 60,
};

@@ -193,3 +188,3 @@

hour: parseInteger(hourStr),
minute: parseInteger(minuteStr)
minute: parseInteger(minuteStr),
};

@@ -209,3 +204,4 @@

// RFC 2822/5322
const rfc2822 = /^(?:(Mon|Tue|Wed|Thu|Fri|Sat|Sun),\s)?(\d{1,2})\s(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)\s(\d{2,4})\s(\d\d):(\d\d)(?::(\d\d))?\s(?:(UT|GMT|[ECMP][SD]T)|([Zz])|(?:([+-]\d\d)(\d\d)))$/;
const rfc2822 =
/^(?:(Mon|Tue|Wed|Thu|Fri|Sat|Sun),\s)?(\d{1,2})\s(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)\s(\d{2,4})\s(\d\d):(\d\d)(?::(\d\d))?\s(?:(UT|GMT|[ECMP][SD]T)|([Zz])|(?:([+-]\d\d)(\d\d)))$/;

@@ -225,3 +221,3 @@ function extractRFC2822(match) {

offHourStr,
offMinuteStr
offMinuteStr,
] = match,

@@ -252,5 +248,8 @@ result = fromStrings(weekdayStr, yearStr, monthStr, dayStr, hourStr, minuteStr, secondStr);

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$/,
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})$/;
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|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})$/;

@@ -277,3 +276,4 @@ function extractRFC1123Or850(match) {

extractISOTime,
extractISOOffset
extractISOOffset,
extractIANAZone
);

@@ -283,3 +283,4 @@ const extractISOWeekTimeAndOffset = combineExtractors(

extractISOTime,
extractISOOffset
extractISOOffset,
extractIANAZone
);

@@ -289,7 +290,12 @@ const extractISOOrdinalDateAndTime = combineExtractors(

extractISOTime,
extractISOOffset
extractISOOffset,
extractIANAZone
);
const extractISOTimeAndOffset = combineExtractors(extractISOTime, extractISOOffset);
const extractISOTimeAndOffset = combineExtractors(
extractISOTime,
extractISOOffset,
extractIANAZone
);
/**
/*
* @private

@@ -334,8 +340,2 @@ */

const extractISOYmdTimeOffsetAndIANAZone = combineExtractors(
extractISOYmd,
extractISOTime,
extractISOOffset,
extractIANAZone
);
const extractISOTimeOffsetAndIANAZone = combineExtractors(

@@ -350,5 +350,5 @@ extractISOTime,

s,
[sqlYmdWithTimeExtensionRegex, extractISOYmdTimeOffsetAndIANAZone],
[sqlYmdWithTimeExtensionRegex, extractISOYmdTimeAndOffset],
[sqlTimeCombinedRegex, extractISOTimeOffsetAndIANAZone]
);
}

@@ -11,3 +11,3 @@ import { parseMillis, isUndefined, untruncateYear, signedOffset, hasOwnProperty } from "./util.js";

function intUnit(regex, post = i => i) {
function intUnit(regex, post = (i) => i) {
return { regex, deser: ([s]) => post(parseDigits(s)) };

@@ -17,3 +17,3 @@ }

const NBSP = String.fromCharCode(160);
const spaceOrNBSP = `( |${NBSP})`;
const spaceOrNBSP = `[ ${NBSP}]`;
const spaceOrNBSPRegExp = new RegExp(spaceOrNBSP, "g");

@@ -41,3 +41,3 @@

deser: ([s]) =>
strings.findIndex(i => stripInsensitivities(s) === stripInsensitivities(i)) + startIndex
strings.findIndex((i) => stripInsensitivities(s) === stripInsensitivities(i)) + startIndex,
};

@@ -56,6 +56,9 @@ }

function escapeToken(value) {
// eslint-disable-next-line no-useless-escape
return value.replace(/[\-\[\]{}()*+?.,\\\^$|#\s]/g, "\\$&");
}
/**
* @param token
* @param {Locale} loc
*/
function unitForToken(token, loc) {

@@ -73,4 +76,4 @@ const one = digitRegex(loc),

fourToSix = digitRegex(loc, "{4,6}"),
literal = t => ({ regex: RegExp(escapeToken(t.val)), deser: ([s]) => s, literal: true }),
unitate = t => {
literal = (t) => ({ regex: RegExp(escapeToken(t.val)), deser: ([s]) => s, literal: true }),
unitate = (t) => {
if (token.literal) {

@@ -82,5 +85,5 @@ return literal(t);

case "G":
return oneOf(loc.eras("short", false), 0);
return oneOf(loc.eras("short"), 0);
case "GG":
return oneOf(loc.eras("long", false), 0);
return oneOf(loc.eras("long"), 0);
// years

@@ -103,5 +106,5 @@ case "y":

case "MMM":
return oneOf(loc.months("short", true, false), 1);
return oneOf(loc.months("short", true), 1);
case "MMMM":
return oneOf(loc.months("long", true, false), 1);
return oneOf(loc.months("long", true), 1);
case "L":

@@ -112,5 +115,5 @@ return intUnit(oneOrTwo);

case "LLL":
return oneOf(loc.months("short", false, false), 1);
return oneOf(loc.months("short", false), 1);
case "LLLL":
return oneOf(loc.months("long", false, false), 1);
return oneOf(loc.months("long", false), 1);
// dates

@@ -153,2 +156,6 @@ case "d":

return simple(oneToNine);
case "uu":
return simple(oneOrTwo);
case "uuu":
return intUnit(one);
// meridiem

@@ -172,9 +179,9 @@ case "a":

case "EEE":
return oneOf(loc.weekdays("short", false, false), 1);
return oneOf(loc.weekdays("short", false), 1);
case "EEEE":
return oneOf(loc.weekdays("long", false, false), 1);
return oneOf(loc.weekdays("long", false), 1);
case "ccc":
return oneOf(loc.weekdays("short", true, false), 1);
return oneOf(loc.weekdays("short", true), 1);
case "cccc":
return oneOf(loc.weekdays("long", true, false), 1);
return oneOf(loc.weekdays("long", true), 1);
// offset/zone

@@ -190,2 +197,6 @@ 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:

@@ -197,3 +208,3 @@ return literal(t);

const unit = unitate(token) || {
invalidReason: MISSING_FTP
invalidReason: MISSING_FTP,
};

@@ -209,3 +220,3 @@

"2-digit": "yy",
numeric: "yyyyy"
numeric: "yyyyy",
},

@@ -216,35 +227,44 @@ month: {

short: "MMM",
long: "MMMM"
long: "MMMM",
},
day: {
numeric: "d",
"2-digit": "dd"
"2-digit": "dd",
},
weekday: {
short: "EEE",
long: "EEEE"
long: "EEEE",
},
dayperiod: "a",
dayPeriod: "a",
hour: {
hour12: {
numeric: "h",
"2-digit": "hh"
"2-digit": "hh",
},
hour24: {
numeric: "H",
"2-digit": "HH",
},
minute: {
numeric: "m",
"2-digit": "mm"
"2-digit": "mm",
},
second: {
numeric: "s",
"2-digit": "ss"
}
"2-digit": "ss",
},
timeZoneName: {
long: "ZZZZZ",
short: "ZZZ",
},
};
function tokenForPart(part, locale, formatOpts) {
function tokenForPart(part, formatOpts, resolvedOpts) {
const { type, value } = part;
if (type === "literal") {
const isSpace = /^\s+$/.test(value);
return {
literal: true,
val: value
literal: !isSpace,
val: isSpace ? " " : value,
};

@@ -255,3 +275,22 @@ }

let val = partTypeStyleToTokenVal[type];
// The user might have explicitly specified hour12 or hourCycle
// if so, respect their decision
// if not, refer back to the resolvedOpts, which are based on the locale
let actualType = type;
if (type === "hour") {
if (formatOpts.hour12 != null) {
actualType = formatOpts.hour12 ? "hour12" : "hour24";
} else if (formatOpts.hourCycle != null) {
if (formatOpts.hourCycle === "h11" || formatOpts.hourCycle === "h12") {
actualType = "hour12";
} else {
actualType = "hour24";
}
} else {
// tokens only differentiate between 24 hours or not,
// so we do not need to check hourCycle here, which is less supported anyways
actualType = resolvedOpts.hour12 ? "hour12" : "hour24";
}
}
let val = partTypeStyleToTokenVal[actualType];
if (typeof val === "object") {

@@ -264,3 +303,3 @@ val = val[style];

literal: false,
val
val,
};

@@ -273,3 +312,3 @@ }

function buildRegex(units) {
const re = units.map(u => u.regex).reduce((f, r) => `${f}(${r.source})`, "");
const re = units.map((u) => u.regex).reduce((f, r) => `${f}(${r.source})`, "");
return [`^${re}$`, units];

@@ -301,3 +340,3 @@ }

function dateTimeFromMatches(matches) {
const toField = token => {
const toField = (token) => {
switch (token) {

@@ -336,11 +375,15 @@ case "S":

let zone;
if (!isUndefined(matches.Z)) {
zone = new FixedOffsetZone(matches.Z);
} else if (!isUndefined(matches.z)) {
let zone = null;
let specificOffset;
if (!isUndefined(matches.z)) {
zone = IANAZone.create(matches.z);
} else {
zone = null;
}
if (!isUndefined(matches.Z)) {
if (!zone) {
zone = new FixedOffsetZone(matches.Z);
}
specificOffset = matches.Z;
}
if (!isUndefined(matches.q)) {

@@ -375,3 +418,3 @@ matches.M = (matches.q - 1) * 3 + 1;

return [vals, zone];
return [vals, zone, specificOffset];
}

@@ -395,21 +438,13 @@

const formatOpts = Formatter.macroTokenToFormatOpts(token.val);
const tokens = formatOptsToTokens(formatOpts, locale);
if (!formatOpts) {
if (tokens == null || tokens.includes(undefined)) {
return token;
}
const formatter = Formatter.create(locale, formatOpts);
const parts = formatter.formatDateTimeParts(getDummyDateTime());
const tokens = parts.map(p => tokenForPart(p, locale, formatOpts));
if (tokens.includes(undefined)) {
return token;
}
return tokens;
}
function expandMacroTokens(tokens, locale) {
return Array.prototype.concat(...tokens.map(t => maybeExpandMacroToken(t, locale)));
export function expandMacroTokens(tokens, locale) {
return Array.prototype.concat(...tokens.map((t) => maybeExpandMacroToken(t, locale)));
}

@@ -423,4 +458,4 @@

const tokens = expandMacroTokens(Formatter.parseFormat(format), locale),
units = tokens.map(t => unitForToken(t, locale)),
disqualifyingUnit = units.find(t => t.invalidReason);
units = tokens.map((t) => unitForToken(t, locale)),
disqualifyingUnit = units.find((t) => t.invalidReason);

@@ -433,3 +468,5 @@ if (disqualifyingUnit) {

[rawMatches, matches] = match(input, regex, handlers),
[result, zone] = matches ? dateTimeFromMatches(matches) : [null, null];
[result, zone, specificOffset] = matches
? dateTimeFromMatches(matches)
: [null, null, undefined];
if (hasOwnProperty(matches, "a") && hasOwnProperty(matches, "H")) {

@@ -440,3 +477,3 @@ throw new ConflictingSpecificationError(

}
return { input, tokens, regex, rawMatches, matches, result, zone };
return { input, tokens, regex, rawMatches, matches, result, zone, specificOffset };
}

@@ -446,4 +483,16 @@ }

export function parseFromTokens(locale, input, format) {
const { result, zone, invalidReason } = explainFromTokens(locale, input, format);
return [result, zone, invalidReason];
const { result, zone, specificOffset, invalidReason } = explainFromTokens(locale, input, format);
return [result, zone, specificOffset, invalidReason];
}
export function formatOptsToTokens(formatOpts, locale) {
if (!formatOpts) {
return null;
}
const formatter = Formatter.create(locale, formatOpts);
const df = formatter.dtFormatter(getDummyDateTime());
const parts = df.formatToParts();
const resolvedOpts = df.resolvedOptions();
return parts.map((p) => tokenForPart(p, formatOpts, resolvedOpts));
}

@@ -8,2 +8,3 @@ /*

import { InvalidArgumentError } from "../errors.js";
import Settings from "../settings.js";

@@ -38,14 +39,2 @@ /**

export function hasIntl() {
try {
return typeof Intl !== "undefined" && Intl.DateTimeFormat;
} catch (e) {
return false;
}
}
export function hasFormatToParts() {
return !isUndefined(Intl.DateTimeFormat.prototype.formatToParts);
}
export function hasRelative() {

@@ -104,13 +93,10 @@ try {

export function padStart(input, n = 2) {
const minus = input < 0 ? "-" : "";
const target = minus ? input * -1 : input;
let result;
if (target.toString().length < n) {
result = ("0".repeat(n) + target).slice(-n);
const isNeg = input < 0;
let padded;
if (isNeg) {
padded = "-" + ("" + -input).padStart(n, "0");
} else {
result = target.toString();
padded = ("" + input).padStart(n, "0");
}
return `${minus}${result}`;
return padded;
}

@@ -126,2 +112,10 @@

export function parseFloating(string) {
if (isUndefined(string) || string === null || string === "") {
return undefined;
} else {
return parseFloat(string);
}
}
export function parseMillis(fraction) {

@@ -164,3 +158,3 @@ // Return undefined (instead of 0) in these cases, where fraction is not set

// covert a calendar object to a local timestamp (epoch, but with the offset baked in)
// convert a calendar object to a local timestamp (epoch, but with the offset baked in)
export function objToLocalTS(obj) {

@@ -180,3 +174,6 @@ let d = Date.UTC(

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);
}

@@ -201,3 +198,3 @@ return +d;

return year;
} else return year > 60 ? 1900 + year : 2000 + year;
} else return year > Settings.twoDigitCutoffYear ? 1900 + year : 2000 + year;
}

@@ -210,3 +207,3 @@

intlOpts = {
hour12: false,
hourCycle: "h23",
year: "numeric",

@@ -216,3 +213,3 @@ month: "2-digit",

hour: "2-digit",
minute: "2-digit"
minute: "2-digit",
};

@@ -224,20 +221,8 @@

const modified = Object.assign({ timeZoneName: offsetFormat }, intlOpts),
intl = hasIntl();
const modified = { timeZoneName: offsetFormat, ...intlOpts };
if (intl && hasFormatToParts()) {
const parsed = new Intl.DateTimeFormat(locale, modified)
.formatToParts(date)
.find(m => m.type.toLowerCase() === "timezonename");
return parsed ? parsed.value : null;
} else if (intl) {
// this probably doesn't work for all locales
const without = new Intl.DateTimeFormat(locale, intlOpts).format(date),
included = new Intl.DateTimeFormat(locale, modified).format(date),
diffed = included.substring(without.length),
trimmed = diffed.replace(/^[, \u200e]+/, "");
return trimmed;
} else {
return null;
}
const parsed = new Intl.DateTimeFormat(locale, modified)
.formatToParts(date)
.find((m) => m.type.toLowerCase() === "timezonename");
return parsed ? parsed.value : null;
}

@@ -268,7 +253,6 @@

export function normalizeObject(obj, normalizer, nonUnitKeys) {
export function normalizeObject(obj, normalizer) {
const normalized = {};
for (const u in obj) {
if (hasOwnProperty(obj, u)) {
if (nonUnitKeys.indexOf(u) >= 0) continue;
const v = obj[u];

@@ -302,3 +286,1 @@ if (v === undefined || v === null) continue;

}
export const ianaRegex = /[A-Za-z_+-]{1,256}(:?\/[A-Za-z_+-]{1,256}(\/[A-Za-z_+-]{1,256})?)?/;

@@ -11,2 +11,3 @@ /**

import { isUndefined, isString, isNumber } from "./util.js";
import SystemZone from "../zones/systemZone.js";

@@ -21,12 +22,9 @@ export function normalizeZone(input, defaultZone) {

const lowered = input.toLowerCase();
if (lowered === "local") return defaultZone;
if (lowered === "default") return defaultZone;
else if (lowered === "local" || lowered === "system") return SystemZone.instance;
else if (lowered === "utc" || lowered === "gmt") return FixedOffsetZone.utcInstance;
else if ((offset = IANAZone.parseGMTOffset(input)) != null) {
// handle Etc/GMT-4, which V8 chokes on
return FixedOffsetZone.instance(offset);
} else if (IANAZone.isValidSpecifier(lowered)) return IANAZone.create(input);
else return FixedOffsetZone.parseSpecifier(lowered) || new InvalidZone(input);
else return FixedOffsetZone.parseSpecifier(lowered) || IANAZone.create(input);
} else if (isNumber(input)) {
return FixedOffsetZone.instance(input);
} else if (typeof input === "object" && input.offset && typeof input.offset === "number") {
} else if (typeof input === "object" && "offset" in input && typeof input.offset === "function") {
// This is dumb, but the instanceof check above doesn't seem to really work

@@ -33,0 +31,0 @@ // so we're duck checking it

@@ -7,3 +7,3 @@ import DateTime from "./datetime.js";

import { hasFormatToParts, hasIntl, hasRelative } from "./impl/util.js";
import { hasRelative } from "./impl/util.js";

@@ -20,7 +20,5 @@ /**

static hasDST(zone = Settings.defaultZone) {
const proto = DateTime.now()
.setZone(zone)
.set({ month: 12 });
const proto = DateTime.now().setZone(zone).set({ month: 12 });
return !zone.universal && proto.offset !== proto.set({ month: 6 }).offset;
return !zone.isUniversal && proto.offset !== proto.set({ month: 6 }).offset;
}

@@ -34,3 +32,3 @@

static isValidIANAZone(zone) {
return IANAZone.isValidSpecifier(zone) && IANAZone.isValidZone(zone);
return IANAZone.isValidZone(zone);
}

@@ -45,3 +43,3 @@

* * If `input` is a string that doesn't refer to a known time zone, a Zone
* instance with {@link Zone.isValid} == false is returned.
* instance with {@link Zone#isValid} == false is returned.
* * If `input is a number, a Zone instance with the specified fixed offset

@@ -72,3 +70,3 @@ * in minutes is returned.

* @example Info.months('long', { outputCalendar: 'islamic' })[0] //=> 'Rabiʻ I'
* @return {[string]}
* @return {Array}
*/

@@ -86,3 +84,3 @@ static months(

* changes the string.
* See {@link months}
* See {@link Info#months}
* @param {string} [length='long'] - the length of the month representation, such as "numeric", "2-digit", "narrow", "short", "long"

@@ -94,3 +92,3 @@ * @param {Object} opts - options

* @param {string} [opts.outputCalendar='gregory'] - the calendar
* @return {[string]}
* @return {Array}
*/

@@ -116,3 +114,3 @@ static monthsFormat(

* @example Info.weekdays('short', { locale: 'ar' })[0] //=> 'الاثنين'
* @return {[string]}
* @return {Array}
*/

@@ -127,4 +125,4 @@ static weekdays(length = "long", { locale = null, numberingSystem = null, locObj = null } = {}) {

* changes the string.
* See {@link weekdays}
* @param {string} [length='long'] - the length of the weekday representation, such as "narrow", "short", "long".
* See {@link Info#weekdays}
* @param {string} [length='long'] - the length of the month representation, such as "narrow", "short", "long".
* @param {Object} opts - options

@@ -134,3 +132,3 @@ * @param {string} [opts.locale=null] - the locale code

* @param {string} [opts.locObj=null] - an existing locale object to use
* @return {[string]}
* @return {Array}
*/

@@ -150,3 +148,3 @@ static weekdaysFormat(

* @example Info.meridiems({ locale: 'my' }) //=> [ 'နံနက်', 'ညနေ' ]
* @return {[string]}
* @return {Array}
*/

@@ -165,3 +163,3 @@ static meridiems({ locale = null } = {}) {

* @example Info.eras('long', { locale: 'fr' }) //=> [ 'avant Jésus-Christ', 'après Jésus-Christ' ]
* @return {[string]}
* @return {Array}
*/

@@ -174,33 +172,11 @@ static eras(length = "short", { locale = null } = {}) {

* Return the set of available features in this environment.
* Some features of Luxon are not available in all environments. For example, on older browsers, timezone support is not available. Use this function to figure out if that's the case.
* Some features of Luxon are not available in all environments. For example, on older browsers, relative time formatting support is not available. Use this function to figure out if that's the case.
* Keys:
* * `zones`: whether this environment supports IANA timezones
* * `intlTokens`: whether this environment supports internationalized token-based formatting/parsing
* * `intl`: whether this environment supports general internationalization
* * `relative`: whether this environment supports relative time formatting
* @example Info.features() //=> { intl: true, intlTokens: false, zones: true, relative: false }
* @example Info.features() //=> { relative: false }
* @return {Object}
*/
static features() {
let intl = false,
intlTokens = false,
zones = false,
relative = false;
if (hasIntl()) {
intl = true;
intlTokens = hasFormatToParts();
relative = hasRelative();
try {
zones =
new Intl.DateTimeFormat("en", { timeZone: "America/New_York" }).resolvedOptions()
.timeZone === "America/New_York";
} catch (e) {
zones = false;
}
}
return { intl, intlTokens, zones, relative };
return { relative: hasRelative() };
}
}
import DateTime, { friendlyDateTime } from "./datetime.js";
import Duration, { friendlyDuration } from "./duration.js";
import Duration from "./duration.js";
import Settings from "./settings.js";
import { InvalidArgumentError, InvalidIntervalError } from "./errors.js";
import Invalid from "./impl/invalid.js";
import Formatter from "./impl/formatter.js";
import * as Formats from "./impl/formats.js";

@@ -30,8 +32,8 @@ const INVALID = "Invalid Interval";

*
* * **Creation** To create an Interval, use {@link fromDateTimes}, {@link after}, {@link before}, or {@link fromISO}.
* * **Accessors** Use {@link start} and {@link end} to get the start and end.
* * **Interrogation** To analyze the Interval, use {@link count}, {@link length}, {@link hasSame}, {@link contains}, {@link isAfter}, or {@link isBefore}.
* * **Transformation** To create other Intervals out of this one, use {@link set}, {@link splitAt}, {@link splitBy}, {@link divideEqually}, {@link merge}, {@link xor}, {@link union}, {@link intersection}, or {@link difference}.
* * **Comparison** To compare this Interval to another one, use {@link equals}, {@link overlaps}, {@link abutsStart}, {@link abutsEnd}, {@link engulfs}.
* * **Output** To convert the Interval into other representations, see {@link toString}, {@link toISO}, {@link toISODate}, {@link toISOTime}, {@link toFormat}, and {@link toDuration}.
* * **Creation** To create an Interval, use {@link Interval.fromDateTimes}, {@link Interval.after}, {@link Interval.before}, or {@link Interval.fromISO}.
* * **Accessors** Use {@link Interval#start} and {@link Interval#end} to get the start and end.
* * **Interrogation** To analyze the Interval, use {@link Interval#count}, {@link Interval#length}, {@link Interval#hasSame}, {@link Interval#contains}, {@link Interval#isAfter}, or {@link Interval#isBefore}.
* * **Transformation** To create other Intervals out of this one, use {@link Interval#set}, {@link Interval#splitAt}, {@link Interval#splitBy}, {@link Interval#divideEqually}, {@link Interval.merge}, {@link Interval.xor}, {@link Interval#union}, {@link Interval#intersection}, or {@link Interval#difference}.
* * **Comparison** To compare this Interval to another one, use {@link Interval#equals}, {@link Interval#overlaps}, {@link Interval#abutsStart}, {@link Interval#abutsEnd}, {@link Interval#engulfs}
* * **Output** To convert the Interval into other representations, see {@link Interval#toString}, {@link Interval#toLocaleString}, {@link Interval#toISO}, {@link Interval#toISODate}, {@link Interval#toISOTime}, {@link Interval#toFormat}, and {@link Interval#toDuration}.
*/

@@ -96,3 +98,3 @@ export default class Interval {

start: builtStart,
end: builtEnd
end: builtEnd,
});

@@ -111,3 +113,3 @@ } else {

static after(start, duration) {
const dur = friendlyDuration(duration),
const dur = Duration.fromDurationLike(duration),
dt = friendlyDateTime(start);

@@ -124,3 +126,3 @@ return Interval.fromDateTimes(dt, dt.plus(dur));

static before(end, duration) {
const dur = friendlyDuration(duration),
const dur = Duration.fromDurationLike(duration),
dt = friendlyDateTime(end);

@@ -134,3 +136,3 @@ return Interval.fromDateTimes(dt.minus(dur), dt);

* @param {string} text - the ISO string to parse
* @param {Object} [opts] - options to pass {@link DateTime.fromISO} and optionally {@link Duration.fromISO}
* @param {Object} [opts] - options to pass {@link DateTime#fromISO} and optionally {@link Duration#fromISO}
* @see https://en.wikipedia.org/wiki/ISO_8601#Time_intervals

@@ -237,3 +239,3 @@ * @return {Interval}

* Returns the count of minutes, hours, days, months, or years included in the Interval, even in part.
* Unlike {@link length} this counts sections of the calendar, not periods of time, e.g. specifying 'day'
* Unlike {@link Interval#length} this counts sections of the calendar, not periods of time, e.g. specifying 'day'
* asks 'what dates are included in this interval?', not 'how many days long is this interval?'

@@ -247,3 +249,3 @@ * @param {string} [unit='milliseconds'] - the unit of time to count.

end = this.end.startOf(unit);
return Math.floor(end.diff(start, unit).get(unit)) + 1;
return Math.floor(end.diff(start, unit).get(unit)) + (end.valueOf() !== this.end.valueOf());
}

@@ -312,4 +314,4 @@

* Split this Interval at each of the specified DateTimes
* @param {...[DateTime]} dateTimes - the unit of time to count.
* @return {[Interval]}
* @param {...DateTime} dateTimes - the unit of time to count.
* @return {Array}
*/

@@ -320,3 +322,3 @@ splitAt(...dateTimes) {

.map(friendlyDateTime)
.filter(d => this.contains(d))
.filter((d) => this.contains(d))
.sort(),

@@ -342,6 +344,6 @@ results = [];

* @param {Duration|Object|number} duration - The length of each resulting interval.
* @return {[Interval]}
* @return {Array}
*/
splitBy(duration) {
const dur = friendlyDuration(duration);
const dur = Duration.fromDurationLike(duration);

@@ -358,3 +360,3 @@ if (!this.isValid || !dur.isValid || dur.as("milliseconds") === 0) {

while (s < this.e) {
const added = this.start.plus(dur.mapUnits(x => x * idx));
const added = this.start.plus(dur.mapUnits((x) => x * idx));
next = +added > +this.e ? this.e : added;

@@ -372,3 +374,3 @@ results.push(Interval.fromDateTimes(s, next));

* @param {number} numberOfParts - The number of Intervals to divide the Interval into.
* @return {[Interval]}
* @return {Array}
*/

@@ -467,18 +469,20 @@ divideEqually(numberOfParts) {

* Combines overlapping and adjacent Intervals.
* @param {[Interval]} intervals
* @return {[Interval]}
* @param {Array} intervals
* @return {Array}
*/
static merge(intervals) {
const [found, final] = intervals.sort((a, b) => a.s - b.s).reduce(
([sofar, current], item) => {
if (!current) {
return [sofar, item];
} else if (current.overlaps(item) || current.abutsStart(item)) {
return [sofar, current.union(item)];
} else {
return [sofar.concat([current]), item];
}
},
[[], null]
);
const [found, final] = intervals
.sort((a, b) => a.s - b.s)
.reduce(
([sofar, current], item) => {
if (!current) {
return [sofar, item];
} else if (current.overlaps(item) || current.abutsStart(item)) {
return [sofar, current.union(item)];
} else {
return [sofar.concat([current]), item];
}
},
[[], null]
);
if (final) {

@@ -492,4 +496,4 @@ found.push(final);

* Return an array of Intervals representing the spans of time that only appear in one of the specified Intervals.
* @param {[Interval]} intervals
* @return {[Interval]}
* @param {Array} intervals
* @return {Array}
*/

@@ -500,3 +504,6 @@ static xor(intervals) {

const results = [],
ends = intervals.map(i => [{ time: i.s, type: "s" }, { time: i.e, type: "e" }]),
ends = intervals.map((i) => [
{ time: i.s, type: "s" },
{ time: i.e, type: "e" },
]),
flattened = Array.prototype.concat(...ends),

@@ -525,8 +532,8 @@ arr = flattened.sort((a, b) => a.time - b.time);

* @param {...Interval} intervals
* @return {[Interval]}
* @return {Array}
*/
difference(...intervals) {
return Interval.xor([this].concat(intervals))
.map(i => this.intersection(i))
.filter(i => i && !i.isEmpty());
.map((i) => this.intersection(i))
.filter((i) => i && !i.isEmpty());
}

@@ -544,5 +551,29 @@

/**
* Returns a localized string representing this Interval. Accepts the same options as the
* Intl.DateTimeFormat constructor and any presets defined by Luxon, such as
* {@link DateTime.DATE_FULL} or {@link DateTime.TIME_SIMPLE}. The exact behavior of this method
* is browser-specific, but in general it will return an appropriate representation of the
* Interval in the assigned locale. Defaults to the system's locale if no locale has been
* specified.
* @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/DateTimeFormat
* @param {Object} [formatOpts=DateTime.DATE_SHORT] - Either a DateTime preset or
* Intl.DateTimeFormat constructor options.
* @param {Object} opts - Options to override the configuration of the start DateTime.
* @example Interval.fromISO('2022-11-07T09:00Z/2022-11-08T09:00Z').toLocaleString(); //=> 11/7/2022 – 11/8/2022
* @example Interval.fromISO('2022-11-07T09:00Z/2022-11-08T09:00Z').toLocaleString(DateTime.DATE_FULL); //=> November 7 – 8, 2022
* @example Interval.fromISO('2022-11-07T09:00Z/2022-11-08T09:00Z').toLocaleString(DateTime.DATE_FULL, { locale: 'fr-FR' }); //=> 7–8 novembre 2022
* @example Interval.fromISO('2022-11-07T17:00Z/2022-11-07T19:00Z').toLocaleString(DateTime.TIME_SIMPLE); //=> 6:00 – 8:00 PM
* @example Interval.fromISO('2022-11-07T17:00Z/2022-11-07T19:00Z').toLocaleString({ weekday: 'short', month: 'short', day: '2-digit', hour: '2-digit', minute: '2-digit' }); //=> Mon, Nov 07, 6:00 – 8:00 p
* @return {string}
*/
toLocaleString(formatOpts = Formats.DATE_SHORT, opts = {}) {
return this.isValid
? Formatter.create(this.s.loc.clone(opts), formatOpts).formatInterval(this)
: INVALID;
}
/**
* Returns an ISO 8601-compliant string representation of this Interval.
* @see https://en.wikipedia.org/wiki/ISO_8601#Time_intervals
* @param {Object} opts - The same options as {@link DateTime.toISO}
* @param {Object} opts - The same options as {@link DateTime#toISO}
* @return {string}

@@ -570,3 +601,3 @@ */

* @see https://en.wikipedia.org/wiki/ISO_8601#Time_intervals
* @param {Object} opts - The same options as {@link DateTime.toISO}
* @param {Object} opts - The same options as {@link DateTime#toISO}
* @return {string}

@@ -580,6 +611,10 @@ */

/**
* Returns a string representation of this Interval formatted according to the specified format string.
* @param {string} dateFormat - the format string. This string formats the start and end time. See {@link DateTime.toFormat} for details.
* @param {Object} opts - options
* @param {string} [opts.separator = ' – '] - a separator to place between the start and end representations
* Returns a string representation of this Interval formatted according to the specified format
* string. **You may not want this.** See {@link Interval#toLocaleString} for a more flexible
* formatting tool.
* @param {string} dateFormat - The format string. This string formats the start and end time.
* See {@link DateTime#toFormat} for details.
* @param {Object} opts - Options.
* @param {string} [opts.separator = ' – '] - A separator to place between the start and end
* representations.
* @return {string}

@@ -586,0 +621,0 @@ */

@@ -9,6 +9,6 @@ import DateTime from "./datetime.js";

import InvalidZone from "./zones/invalidZone.js";
import LocalZone from "./zones/localZone.js";
import SystemZone from "./zones/systemZone.js";
import Settings from "./settings.js";
const VERSION = "1.28.1";
const VERSION = "3.4.0";

@@ -25,4 +25,4 @@ export {

InvalidZone,
LocalZone,
Settings
SystemZone,
Settings,
};

@@ -1,2 +0,2 @@

import LocalZone from "./zones/localZone.js";
import SystemZone from "./zones/systemZone.js";
import IANAZone from "./zones/IANAZone.js";

@@ -8,7 +8,8 @@ import Locale from "./impl/locale.js";

let now = () => Date.now(),
defaultZone = null, // not setting this directly to LocalZone.instance bc loading order issues
defaultZone = "system",
defaultLocale = null,
defaultNumberingSystem = null,
defaultOutputCalendar = null,
throwOnInvalid = false;
twoDigitCutoffYear = 60,
throwOnInvalid;

@@ -39,27 +40,17 @@ /**

/**
* Get the default time zone to create DateTimes in.
* @type {string}
*/
static get defaultZoneName() {
return Settings.defaultZone.name;
}
/**
* Set the default time zone to create DateTimes in. Does not affect existing instances.
* Use the value "system" to reset this value to the system's time zone.
* @type {string}
*/
static set defaultZoneName(z) {
if (!z) {
defaultZone = null;
} else {
defaultZone = normalizeZone(z);
}
static set defaultZone(zone) {
defaultZone = zone;
}
/**
* Get the default time zone object to create DateTimes in. Does not affect existing instances.
* Get the default time zone object currently used to create DateTimes. Does not affect existing instances.
* The default value is the system's time zone (the one set on the machine that runs this code).
* @type {Zone}
*/
static get defaultZone() {
return defaultZone || LocalZone.instance;
return normalizeZone(defaultZone, SystemZone.instance);
}

@@ -116,2 +107,22 @@

/**
* Get the cutoff year after which a string encoding a year as two digits is interpreted to occur in the current century.
* @type {number}
*/
static get twoDigitCutoffYear() {
return twoDigitCutoffYear;
}
/**
* Set the cutoff year after which a string encoding a year as two digits is interpreted to occur in the current century.
* @type {number}
* @example Settings.twoDigitCutoffYear = 0 // cut-off year is 0, so all 'yy' are interpreted as current century
* @example Settings.twoDigitCutoffYear = 50 // '49' -> 1949; '50' -> 2050
* @example Settings.twoDigitCutoffYear = 1950 // interpreted as 50
* @example Settings.twoDigitCutoffYear = 2050 // ALSO interpreted as 50
*/
static set twoDigitCutoffYear(cutoffYear) {
twoDigitCutoffYear = cutoffYear % 100;
}
/**
* Get whether Luxon will throw when it encounters invalid DateTimes, Durations, or Intervals

@@ -118,0 +129,0 @@ * @type {boolean}

@@ -1,2 +0,1 @@

/* eslint no-unused-vars: "off" */
import { ZoneIsAbstractError } from "./errors.js";

@@ -26,2 +25,6 @@

get ianaName() {
return this.name;
}
/**

@@ -32,3 +35,3 @@ * Returns whether the offset is known to be fixed for the whole year.

*/
get universal() {
get isUniversal() {
throw new ZoneIsAbstractError();

@@ -35,0 +38,0 @@ }

@@ -65,2 +65,10 @@ import { formatOffset, signedOffset } from "../impl/util.js";

get ianaName() {
if (this.fixed === 0) {
return "Etc/UTC";
} else {
return `Etc/GMT${formatOffset(-this.fixed, "narrow")}`;
}
}
/** @override **/

@@ -77,3 +85,3 @@ offsetName() {

/** @override **/
get universal() {
get isUniversal() {
return true;

@@ -80,0 +88,0 @@ }

@@ -1,6 +0,4 @@

import { formatOffset, parseZoneInfo, isUndefined, ianaRegex, objToLocalTS } from "../impl/util.js";
import { formatOffset, parseZoneInfo, isUndefined, objToLocalTS } from "../impl/util.js";
import Zone from "../zone.js";
const matchingRegex = RegExp(`^${ianaRegex.source}$`);
let dtfCache = {};

@@ -17,3 +15,4 @@ function makeDTF(zone) {

minute: "2-digit",
second: "2-digit"
second: "2-digit",
era: "short",
});

@@ -28,5 +27,6 @@ }

day: 2,
hour: 3,
minute: 4,
second: 5
era: 3,
hour: 4,
minute: 5,
second: 6,
};

@@ -36,15 +36,17 @@

const formatted = dtf.format(date).replace(/\u200E/g, ""),
parsed = /(\d+)\/(\d+)\/(\d+),? (\d+):(\d+):(\d+)/.exec(formatted),
[, fMonth, fDay, fYear, fHour, fMinute, fSecond] = parsed;
return [fYear, fMonth, fDay, fHour, fMinute, fSecond];
parsed = /(\d+)\/(\d+)\/(\d+) (AD|BC),? (\d+):(\d+):(\d+)/.exec(formatted),
[, fMonth, fDay, fYear, fadOrBc, fHour, fMinute, fSecond] = parsed;
return [fYear, fMonth, fDay, fadOrBc, fHour, fMinute, fSecond];
}
function partsOffset(dtf, date) {
const formatted = dtf.formatToParts(date),
filled = [];
const formatted = dtf.formatToParts(date);
const filled = [];
for (let i = 0; i < formatted.length; i++) {
const { type, value } = formatted[i],
pos = typeToPos[type];
const { type, value } = formatted[i];
const pos = typeToPos[type];
if (!isUndefined(pos)) {
if (type === "era") {
filled[pos] = value;
} else if (!isUndefined(pos)) {
filled[pos] = parseInt(value, 10);

@@ -86,8 +88,8 @@ }

* @example IANAZone.isValidSpecifier("America/New_York") //=> true
* @example IANAZone.isValidSpecifier("Fantasia/Castle") //=> true
* @example IANAZone.isValidSpecifier("Sport~~blorp") //=> false
* @deprecated This method returns false for some valid IANA names. Use isValidZone instead.
* @return {boolean}
*/
static isValidSpecifier(s) {
return !!(s && s.match(matchingRegex));
return this.isValidZone(s);
}

@@ -104,2 +106,5 @@

static isValidZone(zone) {
if (!zone) {
return false;
}
try {

@@ -113,14 +118,2 @@ new Intl.DateTimeFormat("en-US", { timeZone: zone }).format();

// Etc/GMT+8 -> -480
/** @ignore */
static parseGMTOffset(specifier) {
if (specifier) {
const match = specifier.match(/^Etc\/GMT(0|[+-]\d{1,2})$/i);
if (match) {
return -60 * parseInt(match[1]);
}
}
return null;
}
constructor(name) {

@@ -145,3 +138,3 @@ super();

/** @override **/
get universal() {
get isUniversal() {
return false;

@@ -166,9 +159,14 @@ }

const dtf = makeDTF(this.name),
[year, month, day, hour, minute, second] = dtf.formatToParts
? partsOffset(dtf, date)
: hackyOffset(dtf, date),
// work around https://bugs.chromium.org/p/chromium/issues/detail?id=1025564&can=2&q=%2224%3A00%22%20datetimeformat
adjustedHour = hour === 24 ? 0 : hour;
const dtf = makeDTF(this.name);
let [year, month, day, adOrBc, hour, minute, second] = dtf.formatToParts
? partsOffset(dtf, date)
: hackyOffset(dtf, date);
if (adOrBc === "BC") {
year = -Math.abs(year) + 1;
}
// because we're using hour12 and https://bugs.chromium.org/p/chromium/issues/detail?id=1025564&can=2&q=%2224%3A00%22%20datetimeformat
const adjustedHour = hour === 24 ? 0 : hour;
const asUTC = objToLocalTS({

@@ -181,3 +179,3 @@ year,

second,
millisecond: 0
millisecond: 0,
});

@@ -184,0 +182,0 @@

@@ -25,3 +25,3 @@ import Zone from "../zone.js";

/** @override **/
get universal() {
get isUniversal() {
return false;

@@ -28,0 +28,0 @@ }

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is too big to display

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc