Full Code of moment/luxon for AI

master f57f7e4f9c78 cached
149 files
828.1 KB
243.1k tokens
591 symbols
1 requests
Download .txt
Showing preview only (871K chars total). Download the full file or copy to clipboard to get everything.
Repository: moment/luxon
Branch: master
Commit: f57f7e4f9c78
Files: 149
Total size: 828.1 KB

Directory structure:
gitextract_l58zfrk8/

├── .agignore
├── .babelrc
├── .editorconfig
├── .gitattributes
├── .github/
│   ├── ISSUE_TEMPLATE/
│   │   ├── bug_report.md
│   │   └── feature_request.md
│   └── workflows/
│       └── test.yml
├── .gitignore
├── .husky/
│   ├── .gitignore
│   └── pre-commit
├── .prettierrc
├── CHANGELOG.md
├── CONTRIBUTING.md
├── LICENSE.md
├── README.md
├── babel.config.js
├── benchmarks/
│   ├── datetime.js
│   ├── index.js
│   ├── info.js
│   └── package.json
├── codecov.yml
├── docker/
│   ├── Dockerfile
│   ├── build
│   ├── npm
│   ├── push
│   └── readme.md
├── docs/
│   ├── calendars.md
│   ├── formatting.md
│   ├── home.md
│   ├── install.md
│   ├── intl.md
│   ├── math.md
│   ├── matrix.md
│   ├── moment.md
│   ├── parsing.md
│   ├── tour.md
│   ├── upgrading.md
│   ├── validity.md
│   ├── why.md
│   └── zones.md
├── jest.config.js
├── package.json
├── scripts/
│   ├── bootstrap.js
│   ├── deploy-site
│   ├── jest
│   ├── readme.md
│   ├── release
│   ├── repl
│   ├── tag
│   ├── test
│   └── version
├── site/
│   ├── .nojekyll
│   ├── demo/
│   │   ├── demo.css
│   │   ├── demo.js
│   │   ├── global.html
│   │   └── requirejs.html
│   ├── docs/
│   │   ├── _coverpage.md
│   │   └── _sidebar.md
│   ├── index.html
│   └── plugins/
│       ├── dark-theme-toggle.css
│       └── dark-theme-toggle.js
├── src/
│   ├── datetime.js
│   ├── duration.js
│   ├── errors.js
│   ├── impl/
│   │   ├── conversions.js
│   │   ├── diff.js
│   │   ├── digits.js
│   │   ├── english.js
│   │   ├── formats.js
│   │   ├── formatter.js
│   │   ├── invalid.js
│   │   ├── locale.js
│   │   ├── regexParser.js
│   │   ├── tokenParser.js
│   │   ├── util.js
│   │   └── zoneUtil.js
│   ├── info.js
│   ├── interval.js
│   ├── luxon.js
│   ├── package.json
│   ├── settings.js
│   ├── zone.js
│   └── zones/
│       ├── IANAZone.js
│       ├── fixedOffsetZone.js
│       ├── invalidZone.js
│       └── systemZone.js
├── tasks/
│   ├── build.js
│   ├── buildAll.js
│   ├── buildGlobal.js
│   └── buildNode.js
└── test/
    ├── datetime/
    │   ├── create.test.js
    │   ├── degrade.test.js
    │   ├── diff.test.js
    │   ├── dst.test.js
    │   ├── equality.test.js
    │   ├── format.test.js
    │   ├── getters.test.js
    │   ├── info.test.js
    │   ├── invalid.test.js
    │   ├── localeWeek.test.js
    │   ├── many.test.js
    │   ├── math.test.js
    │   ├── misc.test.js
    │   ├── proto.test.js
    │   ├── reconfigure.test.js
    │   ├── regexParse.test.js
    │   ├── relative.test.js
    │   ├── set.test.js
    │   ├── toFormat.test.js
    │   ├── tokenParse.test.js
    │   ├── transform.test.js
    │   ├── typecheck.test.js
    │   └── zone.test.js
    ├── duration/
    │   ├── accuracy.test.js
    │   ├── create.test.js
    │   ├── customMatrix.test.js
    │   ├── equality.test.js
    │   ├── format.test.js
    │   ├── getters.test.js
    │   ├── info.test.js
    │   ├── invalid.test.js
    │   ├── math.test.js
    │   ├── parse.test.js
    │   ├── proto.test.js
    │   ├── reconfigure.test.js
    │   ├── set.test.js
    │   ├── typecheck.test.js
    │   └── units.test.js
    ├── helpers.js
    ├── impl/
    │   └── english.test.js
    ├── info/
    │   ├── features.test.js
    │   ├── listers.test.js
    │   ├── localeWeek.test.js
    │   └── zones.test.js
    ├── interval/
    │   ├── create.test.js
    │   ├── format.test.js
    │   ├── getters.test.js
    │   ├── info.test.js
    │   ├── localeWeek.test.js
    │   ├── many.test.js
    │   ├── parse.test.js
    │   ├── proto.test.js
    │   ├── setter.test.js
    │   └── typecheck.test.js
    └── zones/
        ├── IANA.test.js
        ├── fixedOffset.test.js
        ├── invalid.test.js
        ├── local.test.js
        └── zoneInterface.test.js

================================================
FILE CONTENTS
================================================

================================================
FILE: .agignore
================================================
/build
package-lock.json


================================================
FILE: .babelrc
================================================
{
  "presets": [
    "@babel/preset-env"
  ]
}


================================================
FILE: .editorconfig
================================================
root = true

[*]
charset = utf-8
indent_size = 2
end_of_line = lf
indent_style = space
insert_final_newline = false
trim_trailing_whitespace = true

[*.md]
trim_trailing_whitespace = false


================================================
FILE: .gitattributes
================================================
scripts/* linguist-vendored
docker/* linguist-vendored
site/** linguist-vendored
.husky/* linguist-vendored


================================================
FILE: .github/ISSUE_TEMPLATE/bug_report.md
================================================
---
name: Bug report
about: Create a report to help us improve
title: ""
labels: bug
---

**Describe the bug**
A clear and concise description of what the bug is.

**To Reproduce**
Please share a minimal code example that triggers the problem:

**Actual vs Expected behavior**
A clear and concise description of what you expected to happen.

**Desktop (please complete the following information):**

- OS: [e.g. iOS]
- Browser [e.g. Chrome 84, safari 14.0]
- Luxon version [e.g. 1.25.0]
- Your timezone [e.g. "America/New_York"]

**Additional context**
Add any other context about the problem here.


================================================
FILE: .github/ISSUE_TEMPLATE/feature_request.md
================================================
---
name: Feature request
about: Suggest an idea for this project
title: ""
labels: enhancement
---

**Is your feature request related to a problem? Please describe.**
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]

**Describe the solution you'd like**
A clear and concise description of what you want to happen.

**Describe alternatives you've considered**
A clear and concise description of any alternative solutions or features you've considered.

**Additional context**
Add any other context or screenshots about the feature request here.


================================================
FILE: .github/workflows/test.yml
================================================
name: Test

on:
  push:
    branches: [master]
  pull_request:
    branches: [master]

jobs:
  build-and-test:
    runs-on: ubuntu-latest

    env:
      LANG: en_US.utf8
      LIMIT_JEST: yes
      TZ: America/New_York

    strategy:
      matrix:
        node-version:
          - 18.20.8 # latest 18.x
          - 20.19.4 # latest 20.x
          - 22.17.1 # latest 22.x
          - 24.4.1 # latest 22.x

    steps:
      - uses: actions/checkout@v3
      - name: Use Node.js ${{ matrix.node-version }}
        uses: actions/setup-node@v3
        with:
          node-version: ${{ matrix.node-version }}
          cache: "npm"
      - run: npm ci
      - run: npm run build
      - run: npm run format-check
      - run: npm run test
      - run: npm run site
      - run: bash <(curl -s https://codecov.io/bash)

================================================
FILE: .gitignore
================================================
node_modules
.tern-port
/build
#*
.#*
coverage/
.DS_Store
.external-ecmascript.js
.idea
.vscode
test/scratch.test.js


================================================
FILE: .husky/.gitignore
================================================
_


================================================
FILE: .husky/pre-commit
================================================
#!/bin/sh
. "$(dirname "$0")/_/husky.sh"

npx lint-staged


================================================
FILE: .prettierrc
================================================
{ "printWidth": 100 }


================================================
FILE: CHANGELOG.md
================================================
# Changelog

# 3.7.2 (2025-07-09)
- Fix ES6 packaging

# 3.7.1 (2025-07-09)
- Revert change in ES6 packaging

# 3.7.0 (2025-07-09)
- Added `showZeros` option to `Duration#toHuman`
- Added `Duration#removeZeros` method.
- Added `rounding` option to `DateTime#toRelative`
- Added `precision` option to ISO formatting methods
- Added `signMode` option to `Duration#toFormat`
- Allow escaping single quotes in format strings
- Improve output of `Info.months` and `Info.monthsFormat` for `ja` locale
- Accept lowercase `t` as a separator in ISO strings
- Accept lowercase `z` as an offset in ISO strings
- Reject non-finite numbers where previously only `NaN` was rejected
- Improve the documentation for Interval
- Added a dark theme for the documentation site

# 3.6.1 (2025-03-31)
- Add Fallback for `minimalDays` being removed from Intl.WeekInfo
- Fix various caches when JS keywords like "constructor" are used for names

# 3.6.0 (2025-03-25)
- Add `Interval.lastDateTime`
- Fix a bug that could cause wrong timezone calculations when multiple timezones are in use 

# 3.5.0 (2024-08-03)

- Various performance improvements
- throwOnInvalid causes the constructor to throw if the year is invalid

# 3.4.4 (2023-11-12)

- Localized week support (#1454)
- Added custom inspect for Node (#1526)
- Fix sorting in `Interval.splitAt` (#1524)

# 3.4.3 (2023-09-05)

- Fixes another regression from 3.4.0 (#1496)

# 3.4.2 (2023-08-26)

- Fixes regression from 3.4.1 (#1493)

# 3.4.1 (2023-08-23)

- Fixes for regressions from 3.4.0 (#1482 and #1488)

# 3.4.0 (2023-08-08)

- Fix type checking on input zones
- Fix Islamic months listing
- Fix normalize() for negative inputs

# 3.3.0 (2023-03-03)

- Fix off-by-one in Interval#count (#1308)
- Support formatting for custom zones (#1377)
- Fix parsing for narrow spaces (#1369)
- Handle leap year issue with AD 100 (#1390)
- Allow parsing of just an offset

# 3.2.1 (2023-01-04)

- Fix for RFC-2822 regex vulnerability
- Better handling of BCP tags with -x- extensions

# 3.2.0 (2022-12-29)

- Allow timeZone to be specified as an intl option
- Fix for diff's handling of end-of-month when crossing leap years (#1340)
- Add Interval.toLocaleString() (#1320)

# 3.1.1 (2022-11-28)

- Add Settings.twoDigitCutoffYear

# 3.1.0 (2022-10-31)

- Add Duration.rescale

# 3.0.4 (2022-09-24)

- Fix quarters in diffs (#1279)
- Export package.json in package (#1239)

# 3.0.2 (2022-08-28)

- Lots of doc changes
- Added DateTime.expandFormat
- Added support for custom conversion matrices in Durations

# 3.0.1 (2022-07-09)

- Add DateTime.parseFormatForOpts

# 3.0.0 (2022-07-09)

- Add "default" as an option for specifying a zone, and change "system" to really mean the system zone (breaking change)

# 2.5.0 (2022-07-09)

- Support for ESM-style node imports
- Fix Wednesday parsing for RFC 850 strings
- Increase number of digits allowed in ISO durations

## 2.4.0 (2022-05-08)

- Add support for parsing the ISO zone extension, like `2022-05-08T20:42:00.000-04:00[America/New_York]`
- Add an `extendedZone` option to `toISO()` and `toISOTime`
- Improvements to `DateTime.isInDST()`
- Fix for parsing in Vietnames (and probably other languages)

## 2.3.2 (2022-04-17)

- Fix timezone calculations for negative years
- add week formatting token "w" for durations
- fix weekday computation for years 0-100

## 2.3.1 (2022-02-23)

- Added an `includeOffsetSpace` option to `toSQL` and `toSQLTime`
- Added `toUnixInteger`
- Don't use `-0` when negating durations with zeros in them

## 2.3.0 (2022-01-02)

- Major perf improvements to `toISO()`, `toISODate()`, `toISOTime()`, and `toSQLDate()`
- Fixed date padding for negative years in `toISO()`
- Added Duration#toHuman()

## 2.2.0 (2021-12-10)

- Allow offsets to pick among ambiguous times when both an offset and zone are provided to `fromFormat`
- Fix a floating point bug in `Duration.shiftTo()`

## 2.1.1 (2021-11-08)

- Fix issue in quirky environments that lack `hourCycle` support and sometimes computed offsets 12 hours off

## 2.1.0 (2021-11-07)

- Stop special casing of `Etc/GMT*` zones
- export fromDurationLike
- memoize zone validation
- Support for fractional elements in duration ISO parsing
- Added `uu` and `uuu` tokens for fractional millisecond parsing

## 2.0.2 (2021-08-08)

Fix locale defaulting

## 2.0.0 (2021-07-3)

See [Upgrading section](https://moment.github.io/luxon/#/upgrading?id=_1x-to-20)

## 1.28.0 (2021-07-03)

- Fix ISO parsing for offset specifiers in Year-Ordinal formats

## 1.27.0 (2021-05-08)

- Fix GMT zone parsing for older versions of Node
- Support multiple units in `toRelative`
- Various documentation updates

## 1.26.0 (2021-02-13)

- Add fromISOTime, toISOTime and toMillis to Duration (#803)
- Fix padding of negative years in IsoDate (#871)
- Fix hasSame unit comparison (#798)
- Export VERSION information (#794)
- Durations are considered equal with extra zero units. Fixes #809 (#811)

## 1.25.0 (2020-08-23)

- fix fromFormat with Intl formats containing non-breaking spaces
- Support higher precision in ISO milliseconds
- Some fixes for 00:30 timezones
- Fix some throwOnInvalid for invalid Intervals
- Various doc fixes
- Fix Interval#isSame for empty intervals
- Mark package as side effect-free
- Add support for intervals with a large number of seconds

## 1.24.1 (2020-05-04)

- Remove erroneous `console.log` call

## 1.24.0 (2020-05-03)

- Update polyfills for pollyfilled build

## 1.23.0 (2020-04-02)

- Allow minus sign prefix when creating Duration from ISO

## 1.22.2 (2020-03-25)

- Added more details to error messages for type errors

## 1.22.1 (2020-03-19)

- Added support for ISO basic format to DateTime#toISO

## 1.22.0 (2020-01-26)

- Fix setZone's handling of pre-1970 dates with millisecond components
- Fix keepLocalTime for large jumps near the target zone's DST
- Fix cache perf for toRelative()

## 1.21.3 (2019-11-28)

- Fix parsing of meridiems in macro tokens in newer versions of v8

## 1.21.2 (2019-11-18)

- Fix bug in Chrome Canary that threw off time zone calculations

## 1.21.1 (2019-11-03)

- Fix for quarter parsing
- Some documentation updates

## 1.21.0 (2019-10-30)

- Added quarter support to the parser
- Fix some rounding issues in ISO formatting

## 1.20.0 (2019-10-29)

- Added Duration#mapUnits
- added Interval#toISODate and Interval#toISOTime
- Some documentation fixes

## 1.19.3

- Cache offset values
- Fix handling of negative sub 1-hour offsets

## 1.19.2

- Speculative fix for Node 6

## 1.19.1

- Fix Intl.DateTimeFormat usage for polyfills

## 1.19.0

- Interval#splitAt now ignores input dates outside the interval
- Don't allow decimals in DateTime creation

## 1.18.2

- Fix handling of decimals in DateTime#plus and #minus

## 1.18.1

- Fix validity when adding or subtracting time that exceeds Date max/min boundaries

## 1.18.0

- Add support for macro tokens in the parser

## 1.17.2

- Fix issue with `toRelative` using `style: short` with plural days

## 1.17.1

- Reject out-of-range numbers in DateTime.fromMillis
- Reject 0s in ISO date inputs

## 1.17.0

- DateTime.min and DateTime.max throw if they get the wrong kind of arguments
- Fixed throwOnInvalid logic for Interval
- Added `DATETIME_MED_WITH_WEEKDAY` preset

## 1.16.1

- Catch errors trying to use Intl in weird versions of IE 11

## 1.16.0

- Fixed locale default logic for `DateTime#toFormat("ZZZZ")

## 1.15.0

- Added `formatOffset` to Zones

## 1.14.0

- Allow the zone argument to Interval.fromISO with duration components
- Ignore the zone argument to Duration factory methods

## 1.13.3

- Fix keepLocalTime calculations that span offset changes

## 1.13.2

- Fixed ISO formatting for dates > 999

## 1.13.1

- Performance improvements for regex parsing

## 1.13.0

- Support numberSystem in fromFormat
- Fix validity for bad initial zone specifiers

## 1.12.1

- Fix cross-month diffs in some scenarios
- Fix time zone parsing when the time zone isn't at the end
- Memoize IANA zone creation

## 1.12.0

- Add some explicit CDN support to the NPM package
- Add week token to duration ISO support
- Lots of cleanup and test coverage changes

## 1.11.4

- `setZone("local")` now returns the defaultZone if it is set
- Fixes for the polyfilled build

## 1.11.3

- Allow 24:00 in ISO (and other) strings
- Fix some bugs with the typecheck functions like `DateTime.isDateTime()`

## 1.11.2

- Fixed handling of some characters in fromFormat literal sections
- Handle string values in object arguments to DateTime methods
- Fixed toRelativeCalendar's handling of zones in the base date

## 1.11.1

- Fix DateTime#plus() when spanning across AD 100

## 1.11.0

- Fix low-year handling for IANA zones
- `DateTime#toLocal()` now uses the default locale
- Fix zero duration formatting
- Many documentation fixes

## 1.10.0

- Fix endOf("day") during DSTs (#399)
- Add `Interval#mapEndpoints (#400)
- Add `DateTime#zone` and `Info.normalizeZone` (#404)

## 1.9.0

- Add `DateTime#toRelative` and `DateTime#toRelativeCalendar`

## 1.8.3

- Allow "UTC" in the zone position of `fromSQL`
- Force `isDateTime` and `isDuration` to return booleans in all cases

## 1.8.2

- Trim leading \u200e characters from offset names in Edge 16 and 17

## 1.8.1

- Add `DateTime.fromSeconds` and `DateTime#toSeconds`

## 1.7.1

- Floor the seconds instead of rounding them when outputting the 'X' format
- Change the options to toLocale to override the configuration (the previous options were essentially ignored)

## 1.6.2

- Fixing merge error that resulted in bad error messages

## 1.6.0

- **midly breaking** Rework negative durations
- Fix handling


================================================
FILE: CONTRIBUTING.md
================================================
# Contributing to Luxon

## General guidelines

Patches are welcome. Luxon is at this point just a baby and it could use lots of help. But before you dive in...Luxon is one of those tightly-scoped libraries where the default answer to "should this library do X?" is likely "no". **So ask first!** It might save you some time and energy.

Here are some vague notes on Luxon's design philosophy:

1.  We won't accept patches that can't be internationalized using the JS environment's (e.g. the browser's) native capabilities. This means that most convenient humanization features are out of scope.
1.  We try hard to have a clear definition of what Luxon does and doesn't do. With few exceptions, this is not a "do what I mean" library.
1.  Luxon shouldn't contain simple conveniences that bloat the library to save callers a couple lines of code. Write those lines in your own code.
1.  Most of the complexity of JS module loading compatibility is left to the build. If you have a "this can't be loaded in my bespoke JS module loader" problems, this isn't something you should be solving with changes to the `src` directory. If it's a common use case and is possible to generate with Rollup, it can get its own build command.
1.  We prefer documentation clarifications and gotchas to go in the docstrings, not in the guides on the docs page. Obviously, if the guides are wrong, they should be fixed, but we don't want them to turn into troubleshooting pages. On the other hand, making sure the method-level documentation has ample examples and notes is great.
1.  You'll need to sign a CLA as part of your first pull request to Luxon.

## Building and testing

Building and testing is done through npm scripts. The tests run in Node and require Node 18 with full-icu support. This is because some of the features available in Luxon (like internationalization and time zones) need that stuff and we test it all. On any platform, if you have Node 18 installed with full-icu, you're good to go; just run `scripts/test`. But you probably don't have that, so read on.

### OSX

Mac is easy:
Open the terminal.

```
brew install node --with-full-icu
npm install
./scripts/test
```

If that's for whatever reason a pain, the Linux instructions should also work, as well as the Docker ones.

### Linux

There are two ways to get full-icu support in Linux: build it with that support, or provide it as a module. We'll cover the latter. Assuming you've installed Node 10:

```
npm install
npm install full-icu
./scripts/test
```

Where `scripts/test` is just `NODE_ICU_DATA="$(pwd)/node_modules/full-icu" npm run test`, which is required for making Node load the full-icu module you just installed. You can run all the other npm scripts (e.g. `npm run docs`) directly; they don't require Intl support.

### Windows

If you have [Bash](https://git-scm.com/downloads) or [WSL](https://docs.microsoft.com/en-us/windows/wsl/install-win10), the Linux instructions seem to work fine.

I would love to add instructions for a non-WSL install of the dev env!

### Docker

In case messing with your Node environment just to run Luxon's tests is too much to ask, we've provided a Docker container. You'll need a functioning Docker environment, but the rest is easy:

```
./docker/npm install --ignore-scripts
./docker/npm test
```

## Patch basics

Once you're sure your bugfix or feature makes sense for Luxon, make sure you take these steps:

1.  Be sure to add tests and run them with `scripts/test`
1.  Be sure you run `npm run format` before you commit. Note this will modify your source files to line up with the style guidelines.
1.  Make sure you add or ESDoc annotations appropriately. You can run `npm run docs` to generate the HTML for them. They land in the `build/docs` directory. This also builds the markdown files in `/docs` into the guide on the Luxon website.
1.  To test Luxon in your browser, run `npm run site` and then open `build/demo/global.html`. You can access Luxon classes in the console like `window.luxon.DateTime`.
1.  To test in Node, run `npm run build` and then run something like `var DateTime = require('./build/cjs-browser/luxon').DateTime`.

Luxon uses [Husky](https://github.com/typicode/husky) to run the formatter on your code as a pre-commit hook. You should still run `npm run format` yourself to catch other issues, but this hook will help prevent you from failing the build with a trivial formatting error.

## npm script reference

| Command                      | Function                                |
| ---------------------------- | --------------------------------------- |
| `npm run build`              | Build all the distributable files       |
| `npm run build-node`         | Build just for Node                     |
| `npm run test`               | Run the test suite, but see notes above |
| `npm run format`             | Run the Prettier formatter              |
| `npm run site`               | Build the Luxon website, including docs                 |
| `npm run check-doc-coverage` | Check whether there's full doc coverage |
| `npm run benchmark`          | Run performance benchmarks |


================================================
FILE: LICENSE.md
================================================
Copyright 2019 JS Foundation and other contributors

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.


================================================
FILE: README.md
================================================
# Luxon

[![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]

Luxon is a library for working with dates and times in JavaScript.

```js
DateTime.now().setZone("America/New_York").minus({ weeks: 1 }).endOf("day").toISO();
```

## 🚀 The road to Luxon 4.0

Please [read about and share your feedback](https://github.com/moment/luxon/discussions/1742) on the plans for the next major version of Luxon!

## Upgrading to 3.0

[Guide](https://moment.github.io/luxon/#upgrading)

## Features
 * DateTime, Duration, and Interval types.
 * Immutable, chainable, unambiguous API.
 * Parsing and formatting for common and custom formats.
 * Native time zone and Intl support (no locale or tz files).

## Download/install

[Download/install instructions](https://moment.github.io/luxon/#/install)

## Documentation

* [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)

## Development

See [contributing](CONTRIBUTING.md).

![Phasers to stun][phasers-image]

[license-image]: https://img.shields.io/badge/license-MIT-blue.svg
[license]: LICENSE.md

[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

[npm-url]: https://npmjs.org/package/luxon
[npm-version-image]: https://badge.fury.io/js/luxon.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://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


================================================
FILE: babel.config.js
================================================
module.exports = { presets: ["@babel/preset-env"] };


================================================
FILE: benchmarks/datetime.js
================================================
import Benchmark from "benchmark";
import DateTime from "../src/datetime.js";
import Settings from "../src/settings.js";

function runDateTimeSuite() {
  return new Promise((resolve, reject) => {
    const suite = new Benchmark.Suite();

    const dt = DateTime.now();

    const formatParser = DateTime.buildFormatParser("yyyy/MM/dd HH:mm:ss.SSS");

    suite
      .add("DateTime.now", () => {
        DateTime.now();
      })
      .add("DateTime.fromObject with locale", () => {
        DateTime.fromObject({}, { locale: "fr" });
      })
      .add("DateTime.local with numbers", () => {
        DateTime.local(2017, 5, 15);
      })
      .add("DateTime.local with numbers and zone", () => {
        DateTime.local(2017, 5, 15, 11, 7, 35, { zone: "America/New_York" });
      })
      .add("DateTime.fromISO", () => {
        DateTime.fromISO("1982-05-25T09:10:11.445Z");
      })
      .add("DateTime.fromSQL", () => {
        DateTime.fromSQL("2016-05-14 10:23:54.2346");
      })
      .add("DateTime.fromFormat", () => {
        DateTime.fromFormat("1982/05/25 09:10:11.445", "yyyy/MM/dd HH:mm:ss.SSS");
      })
      .add("DateTime.fromFormat with zone", () => {
        DateTime.fromFormat("1982/05/25 09:10:11.445", "yyyy/MM/dd HH:mm:ss.SSS", {
          zone: "America/Los_Angeles",
        });
      })
      .add("DateTime.fromFormatParser", () => {
        DateTime.fromFormatParser("1982/05/25 09:10:11.445", formatParser);
      })
      .add("DateTime.fromFormatParser with zone", () => {
        DateTime.fromFormatParser("1982/05/25 09:10:11.445", formatParser, {
          zone: "America/Los_Angeles",
        });
      })
      .add("DateTime#setZone", () => {
        dt.setZone("America/Los_Angeles");
      })
      .add("DateTime#toFormat", () => {
        dt.toFormat("yyyy-MM-dd");
      })
      .add("DateTime#toFormat with macro", () => {
        dt.toFormat("T");
      })
      .add("DateTime#toFormat with macro no cache", () => {
        dt.toFormat("T");
        Settings.resetCaches();
      })
      .add("DateTime#format in german", () => {
        dt.setLocale("de-De").toFormat("d. LLL. HH:mm");
      })
      .add("DateTime#format in german and no-cache", () => {
        dt.setLocale("de-De").toFormat("d. LLL. HH:mm");
        Settings.resetCaches();
      })
      .add("DateTime#add", () => {
        dt.plus({ milliseconds: 3434 });
      })
      .add("DateTime#toISO", () => {
        dt.toISO();
      })
      .add("DateTime#toLocaleString", () => {
        dt.toLocaleString();
      })
      .add("DateTime#toLocaleString in utc", () => {
        dt.toUTC().toLocaleString();
      })
      .add("DateTime#toRelativeCalendar", () => {
        dt.toRelativeCalendar({ base: DateTime.now(), locale: "fi" });
      })
      .on("cycle", (event) => {
        console.log(String(event.target));
      })
      .on("complete", function () {
        console.log("Fastest is " + this.filter("fastest").map("name"));
        resolve();
      })
      .on("error", function () {
        reject(this.error);
      })
      .run();
  });
}

const allSuites = [runDateTimeSuite];

export default allSuites;


================================================
FILE: benchmarks/index.js
================================================
import dateTimeSuites from "./datetime.js";
import infoSuites from "./info.js";

const allSuites = [...dateTimeSuites, ...infoSuites];

async function runAllSuites() {
  for (const runSuite of allSuites) {
    await runSuite();
  }
}

runAllSuites();


================================================
FILE: benchmarks/info.js
================================================
import Benchmark from "benchmark";
import Info from "../src/info.js";
import Locale from "../src/impl/locale.js";

function runWeekdaysSuite() {
  return new Promise((resolve, reject) => {
    const locale = Locale.create(null, null, null);

    new Benchmark.Suite()
      .add("Info.weekdays with existing locale", () => {
        Info.weekdays("long", { locObj: locale });
      })
      .add("Info.weekdays", () => {
        Info.weekdays("long");
      })
      .on("cycle", (event) => {
        console.log(String(event.target));
      })
      .on("complete", function () {
        console.log("Fastest is " + this.filter("fastest").map("name"));
        resolve();
      })
      .on("error", function () {
        reject(this.error);
      })
      .run();
  });
}

function runWeekdaysFormatSuite() {
  return new Promise((resolve, reject) => {
    const locale = Locale.create(null, null, null);

    new Benchmark.Suite()
      .add("Info.weekdaysFormat with existing locale", () => {
        Info.weekdaysFormat("long", { locObj: locale });
      })
      .add("Info.weekdaysFormat", () => {
        Info.weekdaysFormat("long");
      })
      .on("cycle", (event) => {
        console.log(String(event.target));
      })
      .on("complete", function () {
        console.log("Fastest is " + this.filter("fastest").map("name"));
        resolve();
      })
      .on("error", function () {
        reject(this.error);
      })
      .run();
  });
}

function runMonthsSuite() {
  return new Promise((resolve, reject) => {
    const locale = Locale.create(null, null, null);
    new Benchmark.Suite()
      .add("Info.months with existing locale", () => {
        Info.months("long", { locObj: locale });
      })
      .add("Info.months", () => {
        Info.months("long");
      })
      .on("cycle", (event) => {
        console.log(String(event.target));
      })
      .on("complete", function () {
        console.log("Fastest is " + this.filter("fastest").map("name"));
        resolve();
      })
      .on("error", function () {
        reject(this.error);
      })
      .run();
  });
}

function runMonthsFormatSuite() {
  return new Promise((resolve, reject) => {
    const locale = Locale.create(null, null, null);

    new Benchmark.Suite()
      .add("Info.monthsFormat with existing locale", () => {
        Info.monthsFormat("long", { locObj: locale });
      })
      .add("Info.monthsFormat", () => {
        Info.monthsFormat("long");
      })
      .on("cycle", (event) => {
        console.log(String(event.target));
      })
      .on("complete", function () {
        console.log("Fastest is " + this.filter("fastest").map("name"));
        resolve();
      })
      .on("error", function () {
        reject(this.error);
      })
      .run();
  });
}

const allSuites = [runMonthsSuite, runMonthsFormatSuite, runWeekdaysSuite, runWeekdaysFormatSuite];

export default allSuites;


================================================
FILE: benchmarks/package.json
================================================
{
  "type": "module"
}


================================================
FILE: codecov.yml
================================================
comment: false
coverage:
  status:
    project:
      default:
        target: auto
        threshold: null
        base: auto


================================================
FILE: docker/Dockerfile
================================================
FROM library/node:15-slim

ENV HUSKY_SKIP_INSTALL=1

ENV LANG=en_US.utf8
ENV LIMIT_JEST=yes
ENV CI=yes
ENV TZ=America/New_York


================================================
FILE: docker/build
================================================
#!/usr/bin/env bash
docker build docker -t icambron/luxon


================================================
FILE: docker/npm
================================================
#!/usr/bin/env bash
docker run -it --rm -v $(pwd):/luxon -w /luxon icambron/luxon npm $@


================================================
FILE: docker/push
================================================
#!/usr/bin/env bash
docker push icambron/luxon


================================================
FILE: docker/readme.md
================================================
Luxon provides a Docker container and some wrapping scripts to make it easier to run the tests.

  1. The Dockerfile is really just here as an FYI. You shouldn't need to interact with it
  1. `npm` is a bash script that runs `npm run [arg]` inside the Docker container.


================================================
FILE: docs/calendars.md
================================================
# Calendars

This covers Luxon's support for various calendar systems. If you don't need to use non-standard calendars, you don't need to read any of this.

## Fully supported calendars

Luxon has full support for Gregorian and ISO Week calendars. What I mean by that is that Luxon can parse dates specified in those calendars, format dates into strings using those calendars, and transform dates using the units of those calendars. For example, here is Luxon working directly with an ISO calendar:

```js
DateTime.fromISO('2017-W23-3').plus({ weeks: 1, days: 2 }).toISOWeekDate(); //=>  '2017-W24-5'
```

The main reason I bring all this is up is to contrast it with the capabilities for other calendars described below.

## Output calendars

Luxon has limited support for other calendaring systems. Which calendars are supported at all is a platform-dependent, but can generally be expected to be these: Buddhist, Chinese, Coptic, Ethioaa, Ethiopic, Hebrew, Indian, Islamic, Islamicc, Japanese, Persian, and ROC. **Support is limited to formatting strings with them**, hence the qualified name "output calendar".

In practice this is pretty useful; you can show users the date in their preferred calendaring system while the software works with dates using Gregorian units or Epoch milliseconds. But the limitations are real enough; Luxon doesn't know how to do things like "add one Islamic month".

The output calendar is a property of the DateTime itself. For example:

```js
var dtHebrew = DateTime.now().reconfigure({ outputCalendar: "hebrew" });
dtHebrew.outputCalendar; //=> 'hebrew'
dtHebrew.toLocaleString() //=> '4 Tishri 5778'
```

You can modulate the structure of that string with arguments to `toLocaleString` (see [the docs on that](formatting.md?id=tolocalestring-strings-for-humans)), but the point here is just that you got the alternative calendar.

### Generally supported calendars

Here's a table of the different calendars with examples generated formatting the same date generated like this:

```js
DateTime.fromObject({ outputCalendar: c }).toLocaleString(DateTime.DATE_FULL);
```

Since Luxon uses the browser's **Intl API**, you can use all the supported calendars.
(See [Intl.Locale.prototype.getCalendars()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/Locale/getCalendars) for a full list)

| Calendar           | Example                  |
| ------------------ | ------------------------ |
| buddhist           | September 24, 2560 BE    |
| chinese            | Eighth Month 5, 2017     |
| coptic             | Tout 14, 1734 ERA1       |
| ethioaa            | Meskerem 14, 7510 ERA0   |
| ethiopic           | Meskerem 14, 2010 ERA1   |
| hebrew             | 4 Tishri 5778            |
| indian             | Asvina 2, 1939 Saka      |
| islamic            | Muharram 4, 1439 AH      |
| islamic-civil      | Muharram 3, 1439 AH      |
| islamic-umalqura   | Muharram 3, 1439 AH      |
| iso8601            | September 24, 2017       |
| japanese           | September 24, 29 Heisei  |
| persian            | Mehr 2, 1396 AP          |
| roc                | September 24, 106 Minguo |



### Default output calendar

You can set the default output calendar for new DateTime instances like this:

```js
Settings.defaultOutputCalendar = 'persian';
```


================================================
FILE: docs/formatting.md
================================================
# Formatting

This section covers creating strings to represent a DateTime. There are three types of formatting capabilities:

1.  Technical formats like ISO 8601 and RFC 2822
2.  Internationalizable human-readable formats
3.  Token-based formatting

## Technical formats (strings for computers)

### ISO 8601

[ISO 8601](https://en.wikipedia.org/wiki/ISO_8601) is the most widely used set of string formats for dates and times. Luxon can _parse_ a wide range of them, but provides direct support for formatting only a few of them:

```js
dt.toISO(); //=> '2017-04-20T11:32:00.000-04:00'
dt.toISODate(); //=> '2017-04-20'
dt.toISOWeekDate(); //=> '2017-W17-7'
dt.toISOTime(); //=> '11:32:00.000-04:00'
```

Generally, you'll want the first one. Use it by default when building or interacting with APIs, communicating times over a wire, etc.

### HTTP and RFC 2822

There are a number of legacy standard date and time formats out there, and Luxon supports some of them. You shouldn't use them unless you have a specific reason to.

```js
dt.toRFC2822(); //=> 'Thu, 20 Apr 2017 11:32:00 -0400'
dt.toHTTP(); //=> 'Thu, 20 Apr 2017 03:32:00 GMT'
```

### Unix timestamps

DateTime objects can also be converted to numerical [Unix timestamps](https://en.wikipedia.org/wiki/Unix_time):

```js
dt.toMillis(); //=> 1492702320000
dt.toSeconds(); //=> 1492702320.000
dt.toUnixInteger(); // => 1492702320
dt.valueOf(); //=> 1492702320000, same as .toMillis()
```

## toLocaleString (strings for humans)

### The basics

Modern browsers (and other JS environments) provide support for human-readable, internationalized strings. Luxon provides convenient support for them, and you should use them anytime you want to display a time to a user. Use `toLocaleString` to do it:

```js
dt.toLocaleString(); //=> '4/20/2017'
dt.toLocaleString(DateTime.DATETIME_FULL); //=> 'April 20, 2017 at 11:32 AM EDT'
dt.setLocale('fr').toLocaleString(DateTime.DATETIME_FULL); //=> '20 avril 2017 à 11:32 UTC−4'
```

### Intl.DateTimeFormat

In the example above, `DateTime.DATETIME_FULL` is one of several convenience formats provided by Luxon. But the arguments are really any object of options that can be provided to [Intl.DateTimeFormat](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/DateTimeFormat). For example:

```js
dt.toLocaleString({ month: 'long', day: 'numeric' }); //=> 'April 20'
```

And that's all the preset is:

```
DateTime.DATETIME_FULL;  //=> {
                         //     year: 'numeric',
                         //     month: 'long',
                         //     day: 'numeric',
                         //     hour: 'numeric',
                         //     minute: '2-digit',
                         //     timeZoneName: 'short'
                         //   }
```

This also means you can modify the presets as you choose:

```js
dt.toLocaleString(DateTime.DATE_SHORT); //=>  '4/20/2017'
var newFormat = {...DateTime.DATE_SHORT, weekday: 'long' };
dt.toLocaleString(newFormat); //=>  'Thursday, 4/20/2017'
```

### Presets

Here's the full set of provided presets using the October 14, 1983 at `13:30:23` as an example.

| Name                         | Description                                                        | Example in en_US                                               | Example in fr                                              |
| ---------------------------- | ------------------------------------------------------------------ | -------------------------------------------------------------- | ---------------------------------------------------------- |
| `DATE_SHORT`                 | short date                                                         | `10/14/1983`                                                   | `14/10/1983`                                               |
| `DATE_MED`                   | abbreviated date                                                   | `Oct 14, 1983`                                                 | `14 oct. 1983`                                             |
| `DATE_MED_WITH_WEEKDAY`      | abbreviated date with abbreviated weekday                          | `Fri, Oct 14, 1983`                                            | `ven. 14 oct. 1983`                                        |
| `DATE_FULL`                  | full date                                                          | `October 14, 1983`                                             | `14 octobre 1983`                                          |
| `DATE_HUGE`                  | full date with weekday                                             | `Friday, October 14, 1983`                                     | `vendredi 14 octobre 1983`                                 |
| `TIME_SIMPLE`                | time                                                               | `1:30 PM`                                                      | `13:30`                                                    |
| `TIME_WITH_SECONDS`          | time with seconds                                                  | `1:30:23 PM`                                                   | `13:30:23`                                                 |
| `TIME_WITH_SHORT_OFFSET`     | time with seconds and abbreviated named offset                     | `1:30:23 PM EDT`                                               | `13:30:23 UTC−4`                                           |
| `TIME_WITH_LONG_OFFSET`      | time with seconds and full named offset                            | `1:30:23 PM Eastern Daylight Time`                             | `13:30:23 heure d’été de l’Est`                            |
| `TIME_24_SIMPLE`             | 24-hour time                                                       | `13:30`                                                        | `13:30`                                                    |
| `TIME_24_WITH_SECONDS`       | 24-hour time with seconds                                          | `13:30:23`                                                     | `13:30:23`                                                 |
| `TIME_24_WITH_SHORT_OFFSET`  | 24-hour time with seconds and abbreviated named offset             | `13:30:23 EDT`                                                 | `13:30:23 UTC−4`                                           |
| `TIME_24_WITH_LONG_OFFSET`   | 24-hour time with seconds and full named offset                    | `13:30:23 Eastern Daylight Time`                               | `13:30:23 heure d’été de l’Est`                            |
| `DATETIME_SHORT`             | short date & time                                                  | `10/14/1983, 1:30 PM`                                          | `14/10/1983 à 13:30`                                       |
| `DATETIME_MED`               | abbreviated date & time                                            | `Oct 14, 1983, 1:30 PM`                                        | `14 oct. 1983 à 13:30`                                     |
| `DATETIME_MED_WITH_WEEKDAY`  | abbreviated date & time with abbreviated weekday                   | `Fri, Oct 14, 1983, 1:30 PM`                                   | `ven. 14 oct. 1983 à 13:30`                                |
| `DATETIME_FULL`              | full date and time with abbreviated named offset                   | `October 14, 1983 at 1:30 PM EDT`                              | `14 octobre 1983 à 13:30 UTC−4`                            |
| `DATETIME_HUGE`              | full date and time with weekday and full named offset              | `Friday, October 14, 1983 at 1:30 PM Eastern Daylight Time`    | `vendredi 14 octobre 1983 à 13:30 heure d’été de l’Est`    |
| `DATETIME_SHORT_WITH_SECONDS`| short date & time with seconds                                     | `10/14/1983, 1:30:23 PM`                                       | `14/10/1983 à 13:30:23`                                    |
| `DATETIME_MED_WITH_SECONDS`  | abbreviated date & time with seconds                               | `Oct 14, 1983, 1:30:23 PM`                                     | `14 oct. 1983 à 13:30:23`                                  |
| `DATETIME_FULL_WITH_SECONDS` | full date and time with abbreviated named offset with seconds      | `October 14, 1983 at 1:30:23 PM EDT`                           | `14 octobre 1983 à 13:30:23 UTC−4`                         |
| `DATETIME_HUGE_WITH_SECONDS` | full date and time with weekday and full named offset with seconds | `Friday, October 14, 1983 at 1:30:23 PM Eastern Daylight Time` | `vendredi 14 octobre 1983 à 13:30:23 heure d’été de l’Est` |

### Intl

`toLocaleString`'s behavior is affected by the DateTime's `locale`, `numberingSystem`, and `outputCalendar` properties. See the [Intl](intl.md) section for more.

## Formatting with tokens (strings for Cthulhu)

This section covers generating strings from DateTimes with programmer-specified formats.

### Consider alternatives

You shouldn't create ad-hoc string formats if you can avoid it. If you intend for a computer to read the string, prefer ISO 8601. If a human will read it, prefer `toLocaleString`. Both are covered above. However, if you have some esoteric need where you need some specific format (e.g. because some other software expects it), then `toFormat` is how you do it.

### toFormat

See `DateTime#toFormat` for the API signature. As a brief motivating example:

```js
DateTime.fromISO('2014-08-06T13:07:04.054').toFormat('yyyy LLL dd'); //=> '2014 Aug 06'
```

The supported tokens are described in the table below.

### Intl

All of the strings (e.g. month names and weekday names) are internationalized by introspecting strings generated by the Intl API. Thus the exact strings you get are implementation-specific.

```js
DateTime.fromISO('2014-08-06T13:07:04.054')
  .setLocale('fr')
  .toFormat('yyyy LLL dd'); //=> '2014 août 06'
```

Note `toFormat` defaults to `en-US`. If you need the string to be internationalized, you need to set the locale explicitly like in the example above (or more preferably, use `toLocaleString`).

### Escaping

You may escape strings using single quotes:

```js
DateTime.now().toFormat("HH 'hours and' mm 'minutes'"); //=> '20 hours and 55 minutes'
```

Single quotes themselves can be escaped by doubling them:
```js
DateTime.now().toFormat("MMM d ''yy"); //=> Apr 7 '25
```

### Standalone vs format tokens

Some tokens have a "standalone" and "format" version. Some languages require different forms of a word based on whether it is part of a longer phrase or just by itself (e.g. "Monday the 22nd" vs "Monday"). Use them accordingly.

```js
var d = DateTime.fromISO('2014-08-06T13:07:04.054').setLocale('ru');
d.toFormat('LLLL'); //=> 'август' (standalone)
d.toFormat('MMMM'); //=> 'августа' (format)
```

### Macro tokens

Some of the formats are "macros", meaning they correspond to multiple components. These use the native Intl API and will order their constituent parts in a locale-friendly way.

```js
DateTime.fromISO('2014-08-06T13:07:04.054').toFormat('ff'); //=> 'Aug 6, 2014, 1:07 PM'
```

The macro options available correspond one-to-one with the preset formats defined for `toLocaleString`.

### Table of tokens

(Examples below given for `2014-08-06T13:07:04.054` considered as a local time in America/New_York).

| Standalone token | Format token | Description                                                    | Example                                                       |
|------------------| ------------ |----------------------------------------------------------------| ------------------------------------------------------------- |
| S                |              | millisecond, no padding                                        | `54`                                                          |
| SSS              |              | millisecond, padded to 3                                       | `054`                                                         |
| u                |              | fractional seconds, functionally identical to SSS              | `054`                                                         |
| uu               |              | fractional seconds, between 0 and 99, padded to 2              | `05`                                                          |
| uuu              |              | fractional seconds, between 0 and 9                            | `0`                                                           |
| s                |              | second, no padding                                             | `4`                                                           |
| ss               |              | second, padded to 2 padding                                    | `04`                                                          |
| m                |              | minute, no padding                                             | `7`                                                           |
| mm               |              | minute, padded to 2                                            | `07`                                                          |
| h                |              | hour in 12-hour time, no padding                               | `1`                                                           |
| hh               |              | hour in 12-hour time, padded to 2                              | `01`                                                          |
| H                |              | hour in 24-hour time, no padding                               | `9`                                                           |
| HH               |              | hour in 24-hour time, padded to 2                              | `13`                                                          |
| Z                |              | narrow offset                                                  | `+5`                                                          |
| ZZ               |              | short offset                                                   | `+05:00`                                                      |
| ZZZ              |              | techie offset                                                  | `+0500`                                                       |
| ZZZZ             |              | abbreviated named offset                                       | `EST`                                                         |
| ZZZZZ            |              | unabbreviated named offset                                     | `Eastern Standard Time`                                       |
| z                |              | IANA zone                                                      | `America/New_York`                                            |
| a                |              | meridiem                                                       | `AM`                                                          |
| d                |              | day of the month, no padding                                   | `6`                                                           |
| dd               |              | day of the month, padded to 2                                  | `06`                                                          |
| c                | E            | day of the week, as number from 1-7 (Monday is 1, Sunday is 7) | `3`                                                           |
| ccc              | EEE          | day of the week, as an abbreviate localized string             | `Wed`                                                         |
| cccc             | EEEE         | day of the week, as an unabbreviated localized string          | `Wednesday`                                                   |
| ccccc            | EEEEE        | day of the week, as a single localized letter                  | `W`                                                           |
| L                | M            | month as an unpadded number                                    | `8`                                                           |
| LL               | MM           | month as a padded number                                       | `08`                                                          |
| LLL              | MMM          | month as an abbreviated localized string                       | `Aug`                                                         |
| LLLL             | MMMM         | month as an unabbreviated localized string                     | `August`                                                      |
| LLLLL            | MMMMM        | month as a single localized letter                             | `A`                                                           |
| y                |              | year, unpadded                                                 | `2014`                                                        |
| yy               |              | two-digit year                                                 | `14`                                                          |
| yyyy             |              | four- to six- digit year, pads to 4                            | `2014`                                                        |
| G                |              | abbreviated localized era                                      | `AD`                                                          |
| GG               |              | unabbreviated localized era                                    | `Anno Domini`                                                 |
| GGGGG            |              | one-letter localized era                                       | `A`                                                           |
| kk               |              | ISO week year, unpadded                                        | `14`                                                          |
| kkkk             |              | ISO week year, padded to 4                                     | `2014`                                                        |
| W                |              | ISO week number, unpadded                                      | `32`                                                          |
| WW               |              | ISO week number, padded to 2                                   | `32`                                                          |
| ii               |              | Local week year, unpadded                                      | `14`                                                          |
| iiii             |              | Local week year, padded to 4                                   | `2014`                                                        |
| n                |              | Local week number, unpadded                                    | `32`                                                          |
| nn               |              | Local week number, padded to 2                                 | `32`                                                          |
| o                |              | ordinal (day of year), unpadded                                | `218`                                                         |
| ooo              |              | ordinal (day of year), padded to 3                             | `218`                                                         |
| q                |              | quarter, no padding                                            | `3`                                                           |
| qq               |              | quarter, padded to 2                                           | `03`                                                          |
| D                |              | localized numeric date                                         | `9/4/2017`                                                    |
| DD               |              | localized date with abbreviated month                          | `Aug 6, 2014`                                                 |
| DDD              |              | localized date with full month                                 | `August 6, 2014`                                              |
| DDDD             |              | localized date with full month and weekday                     | `Wednesday, August 6, 2014`                                   |
| t                |              | localized time                                                 | `9:07 AM`                                                     |
| tt               |              | localized time with seconds                                    | `1:07:04 PM`                                                  |
| ttt              |              | localized time with seconds and abbreviated offset             | `1:07:04 PM EDT`                                              |
| tttt             |              | localized time with seconds and full offset                    | `1:07:04 PM Eastern Daylight Time`                            |
| T                |              | localized 24-hour time                                         | `13:07`                                                       |
| TT               |              | localized 24-hour time with seconds                            | `13:07:04`                                                    |
| TTT              |              | localized 24-hour time with seconds and abbreviated offset     | `13:07:04 EDT`                                                |
| TTTT             |              | localized 24-hour time with seconds and full offset            | `13:07:04 Eastern Daylight Time`                              |
| f                |              | short localized date and time                                  | `8/6/2014, 1:07 PM`                                           |
| ff               |              | less short localized date and time                             | `Aug 6, 2014, 1:07 PM`                                        |
| fff              |              | verbose localized date and time                                | `August 6, 2014, 1:07 PM EDT`                                 |
| ffff             |              | extra verbose localized date and time                          | `Wednesday, August 6, 2014, 1:07 PM Eastern Daylight Time`    |
| F                |              | short localized date and time with seconds                     | `8/6/2014, 1:07:04 PM`                                        |
| FF               |              | less short localized date and time with seconds                | `Aug 6, 2014, 1:07:04 PM`                                     |
| FFF              |              | verbose localized date and time with seconds                   | `August 6, 2014, 1:07:04 PM EDT`                              |
| FFFF             |              | extra verbose localized date and time with seconds             | `Wednesday, August 6, 2014, 1:07:04 PM Eastern Daylight Time` |
| X                |              | unix timestamp in seconds                                      | `1407287224`                                                  |
| x                |              | unix timestamp in milliseconds                                 | `1407287224054`                                               |


================================================
FILE: docs/home.md
================================================
## Luxon

Luxon is a library for dealing with dates and times in JavaScript.

```js
DateTime.now().setZone('America/New_York').minus({weeks:1}).endOf('day').toISO();
```

### Features

 * A nice API for working with datetimes
 * Interval support (from time x to time y)
 * Duration support (14 days, 5 minutes, 33 seconds)
 * [Parsing](parsing.md) and [Formatting](formatting.md) datetimes, intervals, and durations
 * [Internationalization](intl.md) of strings using the Intl API
 * Detailed and unambiguous [math](math.md) operations
 * Built-in handling of [time zones](zones.md)
 * Partial support for multiple [calendar systems](calendars.md)
 
 For more, see the docs on the left, including the  [api docs](api-docs/index.html ':ignore')
 
### Getting started
 
  * [Demo](https://moment.github.io/luxon/demo/global.html ':ignore')
  * Read the [quick tour](tour.md)
  * Browse the topic docs on the left
  * Read the [api docs](api-docs/index.html ':ignore')

Logo by [John Dalziel](https://github.com/crashposition)


================================================
FILE: docs/install.md
================================================
# Install guide

Luxon provides different builds for different JS environments. See below for a link to the right one and instructions on how to use it. Luxon supports all modern platforms, but see [the support matrix](matrix.md) for additional details.

## Basic browser setup

- [Download full](https://moment.github.io/luxon/global/luxon.js)
- [Download minified](https://moment.github.io/luxon/global/luxon.min.js)

You can also load the files from a [CDN](https://www.jsdelivr.com/package/npm/luxon).

Just include Luxon in a script tag. You can access its various classes through the `luxon` global.

```html
<script src="luxon.js"></script>
```

You may wish to alias the classes you use:

```js
var DateTime = luxon.DateTime;
```

## Node.js

Supports Node.js 6+. Install via NPM:

```
npm install --save luxon
```

```js
const { DateTime } = require("luxon");
```

If you want to work with locales, you need ICU support:

 1. **For Node.js 13+, it comes built-in, no action necessary**
 2. For older versions of Node.js (only 12 is supported), you need to install it yourself:
    1. Install a build of Node.js with full ICU baked in, such as via nvm: nvm install <version> -s --with-intl=full-icu --download=all or brew: brew install node --with-full-icu
    2. Install the ICU data externally and point Node.js to it. The instructions on how to do that are below.

The instructions for using full-icu as a package are a little confusing. Node.js can't automatically discover that you've installed it, so you need to tell it where to find the data, like this:

```
npm install full-icu
node --icu-data-dir=./node_modules/full-icu
```

You can also point to the data with an environment var, like this:

```
NODE_ICU_DATA="$(pwd)/node_modules/full-icu" node
```

## AMD (System.js, RequireJS, etc)

- [Download full](https://moment.github.io/luxon/amd/luxon.js)
- [Download minified](https://moment.github.io/luxon/amd/luxon.min.js)

```js
requirejs(["luxon"], function(luxon) {
  //...
});
```

## ES6

- [Download full](https://moment.github.io/luxon/es6/luxon.js)
- [Download minified](https://moment.github.io/luxon/es6/luxon.min.js)

```js
import { DateTime } from "luxon";
```

## Webpack

```
npm install --save luxon
```

```js
import { DateTime } from "luxon";
```

## Types

There are third-party typing files for Flow (via [flow-typed](https://github.com/flowtype/flow-typed)) and TypeScript (via [DefinitelyTyped](https://github.com/DefinitelyTyped/DefinitelyTyped)).

For Flow, use:

```
flow-typed install luxon
```

For TypeScript, use:

```
npm install --save-dev @types/luxon
```

## React Native

React Native >=0.70 works just fine out of the box. Older versions of React Native for Android (or if you disable Hermes) doesn't include Intl support by default, which you need for [a lot of Luxon's functionality](matrix.md).

For React Native >=0.60, you should configure the build flavor of jsc in `android/app/build.gradle`:

```diff
-def jscFlavor = 'org.webkit:android-jsc:+'
+def jscFlavor = 'org.webkit:android-jsc-intl:+'
```

For even older versions of React Native you can use [jsc-android-buildscripts](https://github.com/SoftwareMansion/jsc-android-buildscripts) to fix it.


================================================
FILE: docs/intl.md
================================================
# Intl

Luxon uses the native Intl API to provide easy-to-use internationalization. A quick example:

```js
DateTime.now()
  .setLocale("el")
  .toLocaleString(DateTime.DATE_FULL); //=>  '24 Σεπτεμβρίου 2017'
```

## Making sure you have access to other locales

Please see the [install guide](install.md) for instructions on making sure your platform has access to the Intl APIs and the ICU data to power it. This especially important for Node, which doesn't ship with ICU data by default.

## How locales work

Luxon DateTimes can be configured using [BCP 47](https://tools.ietf.org/html/rfc5646) locale strings specifying the language to use generating or interpreting strings. The native Intl API provides the actual internationalized strings; Luxon just wraps it with a nice layer of convenience and integrates the localization functionality into the rest of Luxon. The Mozilla MDN Intl docs have a [good description](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl#Locale_identification_and_negotiation) of how the `locale` argument works. In Luxon, the methods are different but the semantics are the same, except in that Luxon allows you to specify a numbering system and output calendar independently of the locale string.

The rest of this document will concentrate on what Luxon does when provided with locale information.

## Setting the locale

`locale` is a property of Luxon object. Thus, locale is a sort of setting on the DateTime object, as opposed to an argument you provide the different methods that need internationalized.

You can generally set it at construction time:

```js
var dt = DateTime.fromISO("2017-09-24", { locale: "fr" });
dt.locale; //=> 'fr'
```

In this case, the specified locale didn't change the how the parsing worked (there's nothing localized about it), but it did set the locale property in the resulting instance. For other factory methods, such as `fromFormat`, the locale argument _does_ affect how the string is parsed. See further down for more.

You can change the locale of a DateTime instance (meaning, create a clone DateTime with a different locale) using `setLocale`:

```js
DateTime.now().setLocale("fr").locale; //=> 'fr'
```

`setLocale` is just a convenience for `reconfigure`:

```js
DateTime.now().reconfigure({ locale: "fr" }).locale; //=> 'fr'
```

## Default locale

### Out-of-the-box behavior

By default, the `locale` property of a new DateTime or Duration is the system locale. On a browser, that means whatever the user has their browser or OS language set to. On Node, that usually means en-US.

As a result, `DateTime#toLocaleString`, `DateTime#toLocaleParts`, and other human-readable-string methods like `Info.months` will by default generate strings in the user's locale.

However, note that `DateTime.fromFormat` and `DateTime#toFormat` fall back on en-US. That's because these methods are often used to parse or format strings for consumption by APIs that don't care about the user's locale. So we need to pick a locale and stick with it, or the code will break depending on whose browser it runs in. There's an exception, though: `DateTime#toFormat` can take "macro" formats like "D" that produces localized strings as part of a larger string. These *do* default to the system locale because their entire purpose is to be provide localized strings.

### Setting the default

You can set a default locale so that new instances will always be created with the specified locale:

```js
Settings.defaultLocale = "fr";
DateTime.now().locale; //=> 'fr'
```

Note that this also alters the behavior of `DateTime#toFormat` and `DateTime#fromFormat`.

### Using the system locale in string parsing

You generally don't want `DateTime#fromFormat` and `DateTime#toFormat` to use the system's locale, since your format won't be sensitive to the locale's string ordering. That's why Luxon doesn't behave that way by default. But if you really want that behavior, you can always do this:

```js
Settings.defaultLocale = DateTime.now().resolvedLocaleOptions().locale;
```

## Checking what you got

The local environment may not support the exact locale you asked for. The native Intl API will try to find the best match. If you want to know what that match was, use `resolvedLocaleOpts`:

```js
DateTime.local({ locale: "fr-co" }).resolvedLocaleOptions(); //=> { locale: 'fr',
//     numberingSystem: 'latn',
//     outputCalendar: 'gregory' }
```

## Methods affected by the locale

### Formatting

The most important method affected by the locale setting is `toLocaleString`, which allows you to produce internationalized, human-readable strings.

```js
dt.setLocale("fr").toLocaleString(DateTime.DATE_FULL); //=> '25 septembre 2017'
```

That's the normal way to do it: set the locale as property of the DateTime itself and let the `toLocaleString` inherit it. But you can specify the locale directly to `toLocaleString` too:

```js
dt.toLocaleString({ locale: "es" , ...DateTime.DATE_FULL }); //=> '25 de septiembre de 2017'
```

Ad-hoc formatting also respects the locale:

```js
dt.setLocale("fr").toFormat("MMMM dd, yyyy GG"); //=> 'septembre 25, 2017 après Jésus-Christ'
```

### Parsing

You can [parse](parsing.md) localized strings:

```js
DateTime.fromFormat("septembre 25, 2017 après Jésus-Christ", "MMMM dd, yyyy GG", { locale: "fr" });
```

### Listing

Some of the methods in the `Info` class let you list strings like months, weekdays, and eras, and they can be localized:

```js
Info.months("long", { locale: "fr" }); //=> [ 'janvier', 'février', ...
Info.weekdays("long", { locale: "fr" }); //=> [ 'lundi', 'mardi', ...
Info.eras("long", { locale: "fr" }); //=> [ 'avant Jésus-Christ', 'après Jésus-Christ' ]
```

## numberingSystem

DateTimes also have a `numberingSystem` setting that lets you control what system of numerals is used in formatting. In general, you shouldn't override the numbering system provided by the locale. For example, no extra work is needed to get Arabic numbers to show up in Arabic-speaking locales:

```js
var dt = DateTime.now().setLocale("ar");

dt.resolvedLocaleOptions(); //=> { locale: 'ar',
//     numberingSystem: 'arab',
//     outputCalendar: 'gregory' }

dt.toLocaleString(); //=> '٢٤‏/٩‏/٢٠١٧'
```

For this reason, Luxon defaults its own `numberingSystem` property to null, by which it means "let the Intl API decide". However, you can override it if you want. This example is admittedly ridiculous:

```js
const dt = DateTime.local().reconfigure({ locale: "it", numberingSystem: "beng" });
dt.toLocaleString(DateTime.DATE_FULL); //=> '২৪ settembre ২০১৭'
```

Similar to `locale`, you can set the default numbering system for new instances:

```js
Settings.defaultNumberingSystem = "beng";
```

## Locale-based weeks

Most of Luxon uses the [ISO week date](https://en.wikipedia.org/wiki/ISO_week_date) system when working with week-related data.
This means that the week starts on Monday and the first week of the year is that week, which has 4 or more of its days in January.

This definition works for most use-cases, however locales can define different rules. For example, in many English-speaking countries
the week is said to start on Sunday and the 1 January always defines the first week of the year. This information is
available through the Luxon as well.

Note that your runtime needs to support [`Intl.Locale#getWeekInfo`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/Locale/getWeekInfo) for this to have an effect. If unsupported, Luxon will fall back
to using the ISO week dates.

### Accessing locale-based week info

The `Info` class exposes methods `getStartOfWeek`, `getMinimumDaysInFirstWeek` and `getWeekendWeekdays` for informational
purposes.

### Accessing locale-based week data

```js
const dt = DateTime.local(2022, 1, 1, { locale: "en-US" });
dt.localWeekday // 7, because Saturday is the 7th day of the week in en-US
dt.localWeekNumber // 1, because 1 January is always in the first week in en-US
dt.localWeekYear // 2022, because 1 January is always in the first week in en-US
dt.weeksInLocalWeekYear // 53, because 2022 has 53 weeks in en-US
```

### Using locale-based week data when creating DateTimes

When creating a DateTime instance using `fromObject`, you can use the `localWeekday`, `localWeekNumber` and `localWeekYear`
properties. They will use the same locale that the newly created DateTime will use, either explicitly provided or falling back
to the system default.

```js
const dt = DateTime.fromObject({localWeekYear: 2022, localWeekNumber: 53, localWeekday: 7});
dt.toISODate(); // 2022-12-31
```

### Setting locale-based week data

When modifying an existing DateTime instance using `set`, you can use the `localWeekday`, `localWeekNumber` and `localWeekYear`
properties. They will use the locale of the existing DateTime as reference.

```js
const dt = DateTime.local(2022, 1, 2, { locale: "en-US" });
const modified = dt.set({localWeekNumber: 2});
modified.toISODate(); // 2022-01-08
```

### Locale-based weeks with math

The methods `startOf`, `endOf`, `hasSame` of `DateTime` as well as `count` of `Interval` accept an option `useLocaleWeeks`. 
If enabled, the methods will treat the `week` unit according to the locale, respecting the correct start of the week.

```js
const dt = DateTime.local(2022, 1, 6, { locale: "en-US" });
const startOfWeek = dt.startOf('week', {useLocaleWeeks: true});
startOfWeek.toISODate(); // 2022-01-02, a Sunday
```

### Overriding defaults

You can override the runtime-provided defaults for the week settings using `Settings.defaultWeekSettings`:

```js
Settings.defaultWeekSettings = { firstDay: 7, minimalDays: 1, weekend: [6, 7] }
```

================================================
FILE: docs/math.md
================================================
# Math

This page covers some oddball topics related to date and time math, which has some quirky corner cases.

## Calendar math vs time math

### The basics

Math with dates and times can be unintuitive to programmers. If it's Feb 13, 2017 and I say "in exactly one month", you know I mean March 13. Exactly one month after that is April 13. But because February is a shorter month than March, that means we added a different amount of time in each case. On the other hand, if I said "30 days from February 13", you'd try to figure out what day that landed on in March. Here it is in Luxon:

```js
DateTime.local(2017, 2, 13).plus({ months: 1 }).toISODate() //=> '2017-03-13'

DateTime.local(2017, 2, 13).plus({ days: 30 }).toISODate() //=> '2017-03-15'
```

More generally we can differentiate two modes of math:

 * Calendar math works with higher-order, variable-length units like years and months
 * Time math works with lower-order, constant-length units such as hours, minutes, and seconds.

### Which units use which math?

These units use calendar math:

 * **Years** vary because of leap years.
 * **Months** vary because they're just different lengths.
 * **Days** vary because DST transitions mean some days are 23 or 25 hours long.
 * **Quarters** are always three months, but months vary in length so quarters do too.
 * **Weeks** are always the same number of days, but days vary so weeks do too.
 
These units use time math:

 * **Hours** are always 60 minutes
 * **Minutes** are always 60 seconds
 * **Seconds** are always 1000 milliseconds

### Leap seconds

Luxon ([as JavaScript in general](https://262.ecma-international.org/5.1/#sec-15.9.1.1)) doesn't account for [leap seconds](https://en.wikipedia.org/wiki/Leap_second); as in most programming environments, leap seconds happen as invisible changes to the underlying system's time. This can, in rare cases, cause the same second to "occur" twice from Luxon's perspective.

The practical effect of leaps seconds are quite limited:

1. You can't represent the leap second itself (i.e., `DateTime.utc(2016, 12, 31, 23, 59, 60).isValid` returns `false`).
2. A Luxon `diff()` calculation that crosses a leap second will not exactly match the number of seconds that passed in the outside world. This can come up in rare situations where it matters to your application exactly what happened in the last *n* seconds. Even this is increasingly mitigated by [leap smear](https://developers.google.com/time/smear).

### How to think about calendar math

It's best not to think of calendar math as requiring arcane checks on the lengths of intervening periods. Instead, think of them as **adjusting that unit directly and keeping lower order date components constant**. Let's go back to the Feb 13 + 1 month example. If you didn't have Luxon, you would do something like this to accomplish that:

```js
var d = new Date('2017-02-13')
d.setMonth(d.getMonth() + 1)
d.toLocaleString() //=> '3/13/2017, 12:00:00 AM'
```

And under the covers, that's more or less what Luxon does too. It doesn't boil the operation down to a milliseconds delta because that's not what's being asked. Instead, it fiddles with what it thinks the date should be and then uses the built-in Gregorian calendar to compute the new timestamp.

### DSTs

There's a whole section about this in the [time zones documentation](zones.md?id=math-across-dsts). But here's a quick example (Spring Forward is early on March 12 in my time zone):

```js
var start = DateTime.local(2017, 3, 11, 10);
start.hour                          //=> 10, just for comparison
start.plus({days: 1}).hour          //=> 10, stayed the same
start.plus({hours: 24}).hour        //=> 11, DST pushed forward an hour
```

So in adding a day, we kept the hour at 10, even though that's only 23 hours later.

### Time math

Time math is different. In time math, we're just adjusting the clock, adding or subtracting from the epoch timestamp. Adding 63 hours is really the same as adding 63 hours' worth of milliseconds. Under the covers, Luxon does this exactly the opposite of how it does calendar math; it boils the operation down to milliseconds, computes the new timestamp, and then computes the date out of that.

## Math with multiple units

It's possible to do math with multiple units:

```js
DateTime.fromISO('2017-05-15').plus({months: 2, days: 6}).toISODate(); //=> '2017-07-21'
```

This isn't as simple as it looks. For example, what should you expect this to do?

```js
DateTime.fromISO('2017-04-30').plus({months: 1, days: 1}).toISODate();
```

If the day is added first, we'll get an intermediate value of May 1. Adding a month to that gives us June 1. But if the month is added first, we'll an intermediate value of May 30 and day after that is May 31. (See "Calendar math vs time math" above if this is confusing.) So the order matters.

Luxon has a simple rule for this: **math is done from highest order to lowest order**. So the result of the example above is May 31. This rule isn't logically necessary, but it does seem to reflect what people mean. Of course, Luxon can't enforce this rule if you do the math in separate operations:

```js
DateTime.fromISO('2017-04-30').plus({days: 1}).plus({months: 1}).toISODate() //=> '2017-06-01'
```

It's not a coincidence that Luxon's interface makes it awkward to do this wrong.

## Comparing DateTimes

DateTime implements `#valueOf` to return the epoch timestamp, so you can compare DateTimes with `<`, `>`, `<=`, and `>=`. That lets you find out if one DateTime is after or before another DateTime.

```js
d1 < d2 // is d1 before d2?
```

However, be aware that `===` compares object identity, which is not a useful concept in a library with immutable types. Use `#equals` to compare both the time and additional metadata, such as the locale and time zone. If you're only interested in checking the equality of the timestamps, you can use:

```js
d1.toMillis() === d2.toMillis() // are d1 and d2 the same instant in time?
+d1 === +d2 // same test, using object coercion
```

You may also use `#hasSame` to make more subtle comparisons:

```js
d1.hasSame(d2, 'year');   // both DateTimes have the same calendar year
d1.hasSame(d2, 'day');    // both DateTimes have the same calendar day (which implies they also have the same calendar year and month)
```

Note that these are checking against the calendar. For example, if `d1` is in 2017, calling `hasSame` with "year" asks if d2 is also in 2017, not whether the DateTimes within a year of each other. For that, you'd need `diff` (see below).

If you'd like to compare using a specific unit, you can achieve this by combining `#startOf` and the `#valueOf` comparisons above.

```js
var d1 = DateTime.fromISO('2017-04-30');
var d2 = DateTime.fromISO('2017-04-01');

d2 < d1                                   //=> true
d2.startOf('year') < d1.startOf('year')   //=> false
d2.startOf('month') < d1.startOf('month') //=> false
d2.startOf('day') < d1.startOf('day')     //=> true
```

## Duration math

### Basics

`Durations` are quantities of time, like "3 days and 6 hours". Luxon has no idea *which* 3 days and 6 hours they represent; it's just how Luxon represents those quantities in abstract, unmoored from the timeline. This is both tremendously useful and occasionally confusing. I'm not going to give a detailed tour of their capabilities here (see the API docs for that), but I do want to clear up some of those confusions.

Here's some very basic stuff to get us going:

```js
var dur = Duration.fromObject({ days: 3, hours: 6})

// examine it
dur.toObject()          //=> { days: 3, hours: 6 }

// express in minutes
dur.as('minutes')       //=> 4680

// convert to minutes
dur.shiftTo('minutes').toObject() //=> { minutes: 4680 }

// add to a DateTime
DateTime.fromISO("2017-05-15").plus(dur).toISO() //=> '2017-05-18T06:00:00.000-04:00'
```

### Diffs

You can subtract one time from another to find out how much time there is between them. Luxon's `DateTime.diff` method does this and it returns a Duration. For example:

```js
var end = DateTime.fromISO('2017-03-13');
var start = DateTime.fromISO('2017-02-13');

var diffInMonths = end.diff(start, 'months');
diffInMonths.toObject(); //=> { months: 1 }
```

Notice we had to pick the unit to keep track of the diff in. The default is milliseconds:

```js
var diff = end.diff(start);
diff.toObject() //=> { milliseconds: 2415600000 }
```

Finally, you can diff using multiple units:

```js
var end = DateTime.fromISO('2017-03-13');
var start = DateTime.fromISO('2017-02-11');
end.diff(start, ['months', 'days']).toObject() //=> { months: 1, days: 2 }
```

### Casual vs longterm conversion accuracy

Durations represent bundles of time with specific units, but Luxon allows you to convert between them:

 * `shiftTo` returns a new Duration denominated in the specified units.
 * `as` converts the duration to just that unit and returns its value

```js
var dur = Duration.fromObject({ months: 4, weeks: 2, days: 6 })

dur.as('days')                            //=> 140
dur.shiftTo('days').toObject()            //=> { days: 140 }
dur.shiftTo('weeks', 'hours').toObject()  //=> { weeks: 18, hours: 144 }
```

But how do those conversions actually work? First, uncontroversially:

 * 1 week = 7 days
 * 1 day = 24 hours
 * 1 hour = 60 minutes
 * 1 minute = 60 seconds
 * 1 second = 1000 milliseconds
 
These are always true and you can roll them up and down with consistency (e.g. `1 hour = 60 * 60 * 1000 milliseconds`). However, this isn't really true for the higher order units, which vary in length, even putting DSTs aside. A year is sometimes 365 days long and sometimes 366. Months are 28, 29, 30, or 31 days. By default Luxon converts between these units using what you might call "casual" conversions:

|         | Month | Week | Day |
| ---     | ---   |  --- | --- |
| Year    | 12    |   52 | 365 |
| Quarter | 3     |   13 |  91 |
| Month   |       |    4 |  30 |

These should match your intuition and for most purposes they work well. But they're not just wrong; they're not even self-consistent:

```js
Duration.fromObject({ years:1 }).shiftTo('months').shiftTo('days').as('years') //=> 0.9863013698630136
```

This is because 12 * 30 != 365. These errors can be annoying, but they can also cause significant issues if the errors accumulate:

```js
var dur = Duration.fromObject({ years: 50000 });
DateTime.now().plus(dur.shiftTo('milliseconds')).year //=> 51984
DateTime.now().plus(dur).year                         //=> 52017
```

Those are 33 years apart! So Luxon offers an alternative conversion scheme called "longterm", based on the 400-year calendar cycle:

|         | Month |     Week |       Day |
|----     | ---   |      --- |       --- |
| Year    | 12    |  52.1775 |  365.2425 |
| Quarter |  3    | 13.04435 | 91.310625 |
| Month   |       | 4.348125 | 30.436875 |

You can see why these are irritating to work with, which is why they're not the default.

Luxon methods that create Durations de novo accept an option called `conversionAccuracy`. You can set it to "casual" or "longterm". It's a property of the Duration itself, so any conversions you do use the rule you've picked, and any new Durations you derive from it will retain that property.

```js
Duration.fromObject({ years: 23 }, { conversionAccuracy: 'longterm' });
Duration.fromISO('PY23', { conversionAccuracy: 'longterm' });

end.diff(start, 'days', { conversionAccuracy: 'longterm' })
```

You can also create an accurate Duration out of an existing one:

```js
var pedanticDuration = casualDuration.reconfigure({ conversionAccuracy: 'longterm' });
```

These Durations will do their conversions differently.


### Losing information

Be careful of converting between units. It's easy to lose information. Let's say we converted a diff into days:


```js
var end = DateTime.fromISO('2017-03-13');
var start = DateTime.fromISO('2017-02-13');

var diffInMonths = end.diff(start, 'months');
diffInMonths.as('days'); //=> 30
```

That's our conversion between months and days (you could also do a longterm-accurate conversion; it wouldn't fix the issue ahead). But this isn't the number of days between February 13 and March 13!

```js
var diffInDays = end.diff(start, 'days');
diffInDays.toObject(); //=> { days: 28 }
```

It's important to remember that diffs are Duration objects, and a Duration is just a dumb pile of time units our computation spat out. Unlike an Interval, a Duration doesn't "remember" what the inputs to the diff were. So we lost some information converting between units. This mistake is really common when rolling up:


```js
var diff = end.diff(start); // default unit is milliseconds

// wtf, that's not a month!
diff.as('months'); //=> 0.9319444 

// it's not even the right number of days! (hint: my time zone has a DST)
diff.shiftTo('hours').as('days'); //=> 27.958333333333332
```

Normally you won't run into this problem if you think clearly about what you want to do with a diff. Specifically, make sure you diff in the units you actually want to use. Then Luxon knows to answer the question you really want to ask.

```js
var monthsDiff = end.diff(start, "months");
var daysDiff = end.diff(start, "days");
```

But sometimes you really do want an object that represents the subtraction itself, not the result. `Intervals` can help. Intervals are mostly used to keep track of ranges of time, but they make for "anchored" diffs too. For example:

```js
var end = DateTime.fromISO('2017-03-13');
var start = DateTime.fromISO('2017-02-13');
var i = Interval.fromDateTimes(start, end);

i.length('days');       //=> 28
i.length('months')      //=> 1
```

Because the Interval stores its endpoints and computes `length` on the fly, it retakes the diff each time you query it. Of course, precisely because an Interval *isn't* an abstract bundle of time, it can't be used in places where Durations can. For example, you can't add them to DateTime via `plus()` because Luxon wouldn't know what units to do the math in (see "Calendar vs time math" above). But you can convert the interval into a Duration by picking the units:

```js
i.toDuration('months').toObject(); //=> { months: 1 }
i.toDuration('days').toObject(); //=> { days: 28 }
```

You can even pick multiple units:

```js
end = DateTime.fromISO('2018-05-25');
i = start.until(end);
i.toDuration(['years', 'months', 'days']).toObject(); //=> { years: 1, months: 3, days: 12 }
```

Of course, once you've converted to a Duration, you're back in the same spot you were with the diff case; *further* conversions will be lossy. So the point is to think carefully about what information you have when.


================================================
FILE: docs/matrix.md
================================================
# Support matrix

This page covers what platforms are supported by Luxon and what caveats apply to them.

## Official support

Luxon officially supports the last two versions of the major browsers, with some caveats. The table below shows which of the not-universally-supported features are available in what environments.

| Browser                          | Versions | Intl relative time formatting |
| -------------------------------- | -------- | ----------------------------- |
| Chrome                           | >= 73    | ✓                             |
| Firefox                          | >= 65    | ✓                             |
| Edge                             | >= 79    | ✓                             |
|                                  | 18       | ✗                             |
| Safari                           | >= 14    | ✓                             |
|                                  | 13       | ✗                             |
| iOS Safari (iOS version numbers) | >= 14    | ✓                             |
| Node                             | >= 12    | ✓                             |

- Those capabilities are explained in the next sections, along with possible polyfill options
- "w/ICU" refers to providing Node with ICU data. See the [install](install.md?id=node) for instructions

## Effects of missing features

**If the platforms you're targeting has all its boxes above check off, ignore this section**.

In the support table above, you can see that some environments are missing capabilities.  In the current version of
Luxon, there's only one partially-supported feature, so this is currently pretty simple. (Older versions of Luxon supported
older browsers, so there were nuanced feature caveats. Newer versions will add more caveats as new browser capabilities
become available and Luxon takes advantage of them if they're present.)

1.  **Relative time formatting**. Luxon's support for relative time formatting (e.g. `DateTime#toRelative` and `DateTime#toRelativeCalendar`) depends on Intl.RelativeTimeFormat. Luxon will fall back to using English if that capability is missing.

If the browser lacks these capabilities, Luxon tries its best:

| Feature                                | Full support |  No relative time format |
| -------------------------------------- | ------------ |  ----------------------- |
| Most things                            | OK           |  OK                      |
| `DateTime#toRelative` in en-US         | OK           |  OK                      |
| `DateTime#toRelative` in other locales | Uses English |  Uses English            |


## Older platforms

- **Older versions of both Chrome and Firefox** will most likely work. It's just that I only officially support the last two versions. As you get to older versions of these browsers, the missing capabilities listed above begin to apply to them. (e.g. FF started supporting `formatToParts` in 51 and time zones in 52). I haven't broken that out because it's complicated, Luxon doesn't officially support them, and no one runs them anyway.
- **Older versions of IE** probably won't work at all.
- **Older versions of Node** probably won't work without recompiling Luxon with a different Node target. In which case they'll work with some features missing.

## Other platforms

If the platform you're targeting isn't on the list and you're unsure what caveats apply, you can check which pieces are supported:

```js
Info.features(); //=> { relative: false }
```

Specific notes on other platforms:

- **React Native <0.70 on (specifically) Android** doesn't include Intl support by default, so all the possible-to-be-missing capabilities above are unavailable. To fix this on React Native >=0.60, you should configure the build flavor of jsc in `android/app/build.gradle`:

```diff
-def jscFlavor = 'org.webkit:android-jsc:+'
+def jscFlavor = 'org.webkit:android-jsc-intl:+'
```

For even older versions of React Native you can use [jsc-android-buildscripts](https://github.com/SoftwareMansion/jsc-android-buildscripts) to fix it.


================================================
FILE: docs/moment.md
================================================
# For Moment users

Luxon borrows lots of ideas from [Moment.js](https://momentjs.com), but there are a lot of differences too. This document clarifies what they are.

## Immutability

Luxon's objects are immutable, whereas Moment's are mutable. For example, in Moment:

```js
var m1 = moment();
var m2 = m1.add(1, 'hours');
m1.valueOf() === m2.valueOf(); //=> true
```

This happens because `m1` and `m2` are really the same object; `add()` *mutated* the object to be an hour later. Compare that to Luxon:

```js
var d1 = DateTime.now();
var d2 = d1.plus({ hours: 1 });
d1.valueOf() === d2.valueOf(); //=> false
```

This happens because the `plus` method returns a new instance, leaving `d1` unmodified. It also means that Luxon doesn't require copy constructors or clone methods.

## Major functional differences

1. Months in Luxon are 1-indexed instead of 0-indexed like in Moment and the native Date type.
1. Localizations and time zones are implemented by the native Intl API (or a polyfill of it), instead of by the library itself.
1. Luxon has both a Duration type and an Interval type. The Interval type is like Twix.

## Other API style differences

1. Luxon methods often take option objects as their last parameter
1. Luxon has different static methods for object creation (e.g. `fromISO`), as opposed to Moment's one function that dispatches based on the input
1. Luxon parsers are very strict, whereas Moment's are more lenient.
1. Luxon uses getters instead of accessor methods, so `dateTime.year` instead of `dateTime.year()`
1. Luxon centralizes its "setters", like `dateTime.set({year: 2016, month: 4})` instead of `dateTime.year(2016).month(4)` like in Moment.
1. Luxon's Durations are a separate top-level class.
1. Arguments to Luxon's methods are not automatically coerced into Luxon instances. E.g. `m.diff('2017-04-01')` would be `dt.diff(DateTime.fromISO('2017-04-01'))`.

## DateTime method equivalence

Here's a rough mapping of DateTime methods in Moment to ones in Luxon. I haven't comprehensively documented stuff that's in Luxon but not in Moment, just a few odds and ends that seemed obvious for inclusion; there are more. I've probably missed a few things too.

### Creation

| Operation               | Moment                   | Luxon                                 | Notes                                                                                                                                 |
| ----------------------- | ------------------------ | ------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------- |
| Now                     | `moment()`               | `DateTime.now()`                      |                                                                                                                                       |
| From ISO                | `moment(String)`         | `DateTime.fromISO(String)`            |                                                                                                                                       |
| From RFC 2822           | `moment(String)`         | `DateTime.fromRFC2822(String)`        |                                                                                                                                       |
| From custom format      | `moment(String, String)` | `DateTime.fromFormat(String, String)` | The format tokens differ between Moment and Luxon, such that the same format string cannot be used between the two.                   |
| From object             | `moment(Object)`         | `DateTime.fromObject(Object)`         |                                                                                                                                       |
| From timestamp          | `moment(Number)`         | `DateTime.fromMillis(Number)`         |                                                                                                                                       |
| From JS Date            | `moment(Date)`           | `DateTime.fromJSDate(Date)`           |                                                                                                                                       |
| From civil time         | `moment(Array)`          | `DateTime.local(Number...)`           | Like `DateTime.local(2016, 12, 25, 10, 30)`                                                                                           |
| From UTC civil time     | `moment.utc(Array)`      | `DateTime.utc(Number...)`             | Moment also uses `moment.utc()` to take other arguments. In Luxon, use the appropriate method and pass in the `{ zone: 'utc'}` option |
| Clone                   | `moment(Moment)`         | N/A                                   | Immutability makes this pointless; just reuse the object                                                                              |
| Use the string's offset | `parseZone`              | See note                              | Methods taking strings that can specify offset or zone take a `setZone` argument                                                      |

### Getters and setters

#### Basic information getters

| Property | Moment      | Luxon     | Notes                                            |
| -------- | ----------- | --------- | ------------------------------------------------ |
| Validity | `isValid()` | `isValid` | See also `invalidReason`                         |
| Locale   | `locale()`  | `locale`  |                                                  |
| Zone     | `tz()`      | `zone`    | Moment requires a plugin for this, but not Luxon |

#### Unit getters

| Property               | Moment                               | Luxon         | Notes                                  |
| ---------------------- | ------------------------------------ | ------------- | -------------------------------------- |
| Year                   | `year()`                             | `year`        |                                        |
| Month                  | `month()`                            | `month`       |                                        |
| Day of month           | `date()`                             | `day`         |                                        |
| Day of week            | `day()`, `weekday()`, `isoWeekday()` | `weekday`     | 1-7, Monday is 1, Sunday is 7, per ISO |
| Day of year            | `dayOfYear()`                        | `ordinal`     |                                        |
| Hour of day            | `hour()`                             | `hour`        |                                        |
| Minute of hour         | `minute()`                           | `minute`      |                                        |
| Second of minute       | `second()`                           | `second`      |                                        |
| Millisecond of seconds | `millisecond()`                      | `millisecond` |                                        |
| Week of ISO week year  | `weekYear`, `isoWeekYear`            | `weekYear`    |                                        |
| Quarter                | `quarter`                            | None          | Just divide the months by 3            |

#### Programmatic get and set

For programmatic getting and setting, Luxon and Moment are very similar here:

| Operation  | Moment                | Luxon         | Notes                                   |
| ---------- | --------------------- | ------------- | --------------------------------------- |
| get value  | `get(String)`         | `get(String)` |                                         |
| set value  | `set(String, Number)` | None          |                                         |
| set values | `set(Object)`         | `set(Object)` | Like `dt.set({ year: 2016, month: 3 })` |

### Transformation

| Operation          | Moment                     | Luxon               | Notes                                   |
| ------------------ | -------------------------- | ------------------- | --------------------------------------- |
| Addition           | `add(Number, String)`      | `plus(Object)`      | Like `dt.plus({ months: 3, days: 2 })`  |
| Subtraction        | `subtract(Number, String)` | `minus(Object)`     | Like `dt.minus({ months: 3, days: 2 })` |
| Start of unit      | `startOf(String)`          | `startOf(String)`   |                                         |
| End of unit        | `endOf(String)`            | `endOf(String)`     |                                         |
| Change unit values | `set(Object)`              | `set(Object)`       | Like `dt.set({ year: 2016, month: 3 })` |
| Change time zone   | `tz(String)`               | `setZone(string)`   | Luxon doesn't require a plugin          |
| Change zone to utc | `utc()`                    | `toUTC()`           |                                         |
| Change local zone  | `local()`                  | `toLocal()`         |                                         |
| Change offset      | `utcOffset(Number)`        | None                | Set the zone instead                    |
| Change locale      | `locale(String)`           | `setLocale(String)` |                                         |

### Query

| Question                                   | Moment                  | Luxon                                            | Notes                                                                                           |
| ------------------------------------------ | ----------------------- | ------------------------------------------------ | ----------------------------------------------------------------------------------------------- |
| Is this time before that time?             | `m1.isBefore(m2)`       | `dt1 < dt2`                                      | The Moment versions of these take a unit. To do that in Luxon, use `startOf` on both instances. |
| Is this time after that time?              | `m1.isAfter(m2)`        | `dt1 > dt2`                                      |                                                                                                 |
| Is this time the same or before that time? | `m1.isSameOrBefore(m2)` | `dt1 <= dt2`                                     |                                                                                                 |
| Is this time the same or after that time?  | `m1.isSameOrAfter(m2)`  | `dt1 >= dt2`                                     |                                                                                                 |
| Do these two times have the same [unit]?   | `m1.isSame(m2, unit)`   | `dt1.hasSame(dt2, unit)`                         |                                                                                                 |
| Is this time's [unit] before that time's?  | `m1.isBefore(m2, unit)` | `dt1.startOf(unit) < dt2.startOf(unit)`          |                                                                                                 |
| Is this time's [unit] after that time's?   | `m1.isAfter(m2, unit)`  | `dt1.startOf(unit) > dt2.startOf(unit)`          |                                                                                                 |
| Is this time between these two times?      | `m1.isBetween(m2, m3)`  | `Interval.fromDateTimes(dt2, dt3).contains(dt1)` |                                                                                                 |
| Is this time inside a DST                  | `isDST()`               | `isInDST`                                        |                                                                                                 |
| Is this time's year a leap year?           | `isInLeapYear()`        | `isInLeapYear`                                   |                                                                                                 |
| How many days are in this time's month?    | `daysInMonth()`         | `daysInMonth`                                    |                                                                                                 |
| How many days are in this time's year?     | None                    | `daysInYear`                                     |                                                                                                 |

### Output

#### Basics

See the [formatting guide](formatting.md) for more about the string-outputting methods.

| Output           | Moment         | Luxon                       | Notes                                                                                                                                             |
| ---------------- | -------------- | --------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- |
| simple string    | `toString()`   | `toString()`                | Luxon just uses ISO 8601 for this. See Luxon's `toLocaleString()`                                                                                 |
| full ISO 8601    | `iso()`        | `toISO()`                   |                                                                                                                                                   |
| ISO date only    | None           | `toISODate()`               |                                                                                                                                                   |
| ISO time only    | None           | `toISOTime()`               |                                                                                                                                                   |
| custom format    | `format(...)`  | `toFormat(...)`             | The format tokens differ between Moment and Luxon, such that the same format string cannot be used between the two. Note `toFormat` is meant to be used for machine-readable formats. For anything human-readable, you really want to use `toLocaleString()` instead. |
| RFC 2822         |                | `toRFC2822()`               |                                                                                                                                                   |
| HTTP date string |                | `toHTTP()`                  |                                                                                                                                                   |
| JS Date          | `toDate()`     | `toJSDate()`                |                                                                                                                                                   |
| Epoch time       | `valueOf()`    | `toMillis()` or `valueOf()` |                                                                                                                                                   |
| Object           | `toObject()`   | `toObject()`                |                                                                                                                                                   |
| Duration         | `diff(Moment)` | `diff(DateTime)`            | Moment's diff returns a count of milliseconds, but Luxon's returns a Duration. To replicate the Moment behavior, use `dt1.diff(d2).milliseconds`. |

#### Humanization

Luxon has `toRelative` and `toRelativeCalendar`. For internationalization, they use Intl.RelativeTimeFormat (or fall back to English when it is not supported by the browser).

| Operation            | Moment         | Luxon                                         |
| -------------------- | -------------- | --------------------------------------------- |
| Time from now        | `fromNow()`    | `toRelative()`                                |
| Time from other time | `from(Moment)` | `toRelative({ base: DateTime })`              |
| Time to now          | `toNow()`      | `DateTime.local().toRelative({ base: this })` |
| Time to other time   | `to(Moment)`   | `otherTime.toRelative({ base: this })`        |
| "Calendar time"      | `calendar()`   | `toRelativeCalendar()`                        |

## Durations

Moment Durations and Luxon Durations are broadly similar in purpose and capabilities. The main differences are:

1.  Luxon durations have more sophisticated conversion capabilities. They can convert from one set of units to another using `shiftTo`. They can also be configured to use different unit conversions. See [Duration Math](math.md?id=duration-math) for more.
1.  Luxon does not (yet) have an equivalent of Moment's Duration `humanize` method. Luxon will add that when [Intl.UnitFormat](https://github.com/tc39/proposal-intl-unit-format) is supported by browsers.
1.  Like DateTimes, Luxon Durations have separate methods for creating objects from different sources.

See the `Duration` API docs for more.

## Intervals

Moment doesn't have direct support intervals, which must be provided by plugins like Twix or moment-range. Luxon's Intervals have similar capabilities to theirs, with the exception of the humanization features. See the `Interval` API docs for more.


================================================
FILE: docs/parsing.md
================================================
# Parsing

Luxon is not an NLP tool and isn't suitable for all date parsing jobs. But it can do some parsing:

1.  Direct support for several well-known formats, including most valid ISO 8601 formats
2.  An ad-hoc parser for parsing specific formats

## Parsing technical formats

### ISO 8601

Luxon supports a wide range of valid ISO 8601 formats through the `fromISO` method.

```js
DateTime.fromISO("2016-05-25");
```

All of these are parsable by `fromISO`:

```
2016
2016-05
201605
2016-05-25
20160525
2016-05-25T09
2016-05-25T09:24
2016-05-25T09:24:15
2016-05-25T09:24:15.123
2016-05-25T0924
2016-05-25T092415
2016-05-25T092415.123
2016-05-25T09:24:15,123
2016-W21-3
2016W213
2016-W21-3T09:24:15.123
2016W213T09:24:15.123
2016-200
2016200
2016-200T09:24:15.123
09:24
09:24:15
09:24:15.123
09:24:15,123
```

- In addition, all the times support offset arguments like "Z" and "+06:00".
- Missing lower-order values are always set to the minimum possible value; i.e. it always parses to a full DateTime. For example, "2016-05-25" parses to midnight of that day. "2016-05" parses to the first of the month, etc.
- The time is parsed as a local time if no offset is specified, but see the method docs to see your options, and also check out [time zone docs](zones.md) for more details.

### HTTP and RFC2822

Luxon also provides parsing for strings formatted according to RFC 2822 and the HTTP header specs (RFC 850 and 1123):

```js
DateTime.fromRFC2822("Tue, 01 Nov 2016 13:23:12 +0630");
DateTime.fromHTTP("Sunday, 06-Nov-94 08:49:37 GMT");
DateTime.fromHTTP("Sun, 06 Nov 1994 08:49:37 GMT");
```

### SQL

Luxon accepts SQL dates, times, and datetimes, via `fromSQL`:

```js
DateTime.fromSQL("2017-05-15");
DateTime.fromSQL("2017-05-15 09:24:15");
DateTime.fromSQL("09:24:15");
```

It works similarly to `fromISO`, so see above for additional notes.

### Unix timestamps

Luxon can parse numerical [Unix timestamps](https://en.wikipedia.org/wiki/Unix_time):

```js
DateTime.fromMillis(1542674993410);
DateTime.fromSeconds(1542674993);
```

Both methods accept the same options, which allow you to specify a timezone, calendar, and/or numbering system.

### JS Date Object

A native JS `Date` object can be converted into a `DateTime` using `DateTime.fromJSDate`.

An optional `zone` parameter can be provided to set the zone on the resulting object.


## Ad-hoc parsing

### Consider alternatives

You generally shouldn't use Luxon to parse arbitrarily formatted date strings:

1.  If the string was generated by a computer for programmatic access, use a standard format like ISO 8601. Then you can parse it using `DateTime.fromISO`.
2.  If the string is typed out by a human, it may not conform to the format you specify when asking Luxon to parse it. Luxon is quite strict about the format matching the string exactly.

Sometimes, though, you get a string from some legacy system in some terrible ad-hoc format and you need to parse it.

### fromFormat

See `DateTime.fromFormat` for the method signature. A brief example:

```js
DateTime.fromFormat("May 25 1982", "LLLL dd yyyy");
```

### Intl

Luxon supports parsing internationalized strings:

```js
DateTime.fromFormat("mai 25 1982", "LLLL dd yyyy", { locale: "fr" });
```

Note, however, that Luxon derives the list of strings that can match, say, "LLLL" (and their meaning) by introspecting the environment's Intl implementation. Thus the exact strings may in some cases be environment-specific. You also need the Intl API available on the target platform (see the [support matrix](matrix.md)).

### Limitations

Not every token supported by `DateTime#toFormat` is supported in the parser. For example, there's no `ZZZZ` or `ZZZZZ` tokens. This is for a few reasons:

- Luxon relies on natively-available functionality that only provides the mapping in one direction. We can ask what the named offset is and get "Eastern Standard Time" but not ask what "Eastern Standard Time" is most likely to mean.
- Some things are ambiguous. There are several Eastern Standard Times in different countries and Luxon has no way to know which one you mean without additional information (such as that the zone is America/New_York) that would make EST superfluous anyway. Similarly, the single-letter month and weekday formats (EEEEE) that are useful in displaying calendars graphically can't be parsed because of their ambiguity.
- Because of the limitations above, Luxon also doesn't support the "macro" tokens that include offset names, such as "ttt" and "FFFF".

### Parsing Two Digit Years

In order to parse a two digit string as a year (or ISO week year), the `yy` (and `kk`) token must use a cutoff year after which the year being parsed is interpreted as referring to the current century. By default, the cutoff year is set to 60, meaning that the string "60" is parsed as the year 2060, and the string "61" is parsed as the year 1961. The cutoff year can be configured using `Settings.twoDigitCutoffYear`.

### Debugging

There are two kinds of things that can go wrong when parsing a string: a) you make a mistake with the tokens or b) the information parsed from the string does not correspond to a valid date. To help you sort that out, Luxon provides a method called `fromFormatExplain`. It takes the same arguments as `fromFormat` but returns a map of information about the parse that can be useful in debugging.

For example, here the code is using "MMMM" where "MMM" was needed. You can see the regex Luxon uses and see that it didn't match anything:

```js
> DateTime.fromFormatExplain("Aug 6 1982", "MMMM d yyyy")

{ input: 'Aug 6 1982',
  tokens:
   [ { literal: false, val: 'MMMM' },
     { literal: false, val: ' ' },
     { literal: false, val: 'd' },
     { literal: false, val: ' ' },
     { literal: false, val: 'yyyy' } ],
  regex: '(January|February|March|April|May|June|July|August|September|October|November|December)( )(\\d\\d?)( )(\\d{4})',
  matches: {},
  result: {},
  zone: null }
```

If you parse something and get an invalid date, the debugging steps are slightly different. Here, we're attempting to parse August 32nd, which doesn't exist:

```js
var d = DateTime.fromFormat("August 32 1982", "MMMM d yyyy");
d.isValid; //=> false
d.invalidReason; //=> 'day out of range'
```

For more on validity and how to debug it, see [validity](validity.md). You may find more comprehensive tips there. But as it applies specifically to `fromFormat`, again try `fromFormatExplain`:

```js
> DateTime.fromFormatExplain("August 32 1982", "MMMM d yyyy")

{ input: 'August 32 1982',
  tokens:
   [ { literal: false, val: 'MMMM' },
     { literal: false, val: ' ' },
     { literal: false, val: 'd' },
     { literal: false, val: ' ' },
     { literal: false, val: 'yyyy' } ],
  regex: '(January|February|March|April|May|June|July|August|September|October|November|December)( )(\\d\\d?)( )(\\d{4})',
  matches: { M: 8, d: 32, y: 1982 },
  result: { month: 8, day: 32, year: 1982 },
  zone: null }
```

Because Luxon was able to parse the string without difficulty, the output is a lot richer. And you can see that the "day" field is set to 32. Combined with the "out of range" explanation above, that should clear up the situation.

### Table of tokens

(Examples below given for `2014-08-06T13:07:04.054` considered as a local time in America/New_York). Note that many tokens supported by the [formatter](formatting.md) are **not** supported by the parser.

| Standalone token | Format token | Description                                                    | Example                     |
| ---------------- | ------------ | ----------------------------------------------------------------- | --------------------------- |
| S                |              | millisecond, no padding                                           | `54`                        |
| SSS              |              | millisecond, padded to 3                                          | `054`                       |
| u                |              | fractional seconds, (5 is a half second, 54 is slightly more)     | `54`                        |
| uu               |              | fractional seconds, (one or two digits)                           | `05`                        |
| uuu              |              | fractional seconds, (only one digit)                              | `5`                         |
| s                |              | second, no padding                                                | `4`                         |
| ss               |              | second, padded to 2 padding                                       | `04`                        |
| m                |              | minute, no padding                                                | `7`                         |
| mm               |              | minute, padded to 2                                               | `07`                        |
| h                |              | hour in 12-hour time, no padding                                  | `1`                         |
| hh               |              | hour in 12-hour time, padded to 2                                 | `01`                        |
| H                |              | hour in 24-hour time, no padding                                  | `13`                        |
| HH               |              | hour in 24-hour time, padded to 2                                 | `13`                        |
| Z                |              | narrow offset                                                     | `+5`                        |
| ZZ               |              | short offset                                                      | `+05:00`                    |
| ZZZ              |              | techie offset                                                     | `+0500`                     |
| z                |              | IANA zone                                                         | `America/New_York`          |
| a                |              | meridiem                                                          | `AM`                        |
| d                |              | day of the month, no padding                                      | `6`                         |
| dd               |              | day of the month, padded to 2                                     | `06`                        |
| E                | c            | day of the week, as number from 1-7 (Monday is 1, Sunday is 7)    | `3`                         |
| EEE              | ccc          | day of the week, as an abbreviate localized string                | `Wed`                       |
| EEEE             | cccc         | day of the week, as an unabbreviated localized string             | `Wednesday`                 |
| M                | L            | month as an unpadded number                                       | `8`                         |
| MM               | LL           | month as an padded number                                         | `08`                        |
| MMM              | LLL          | month as an abbreviated localized string                          | `Aug`                       |
| MMMM             | LLLL         | month as an unabbreviated localized string                        | `August`                    |
| y                |              | year, 1-6 digits, very literally                                  | `2014`                      |
| yy               |              | two-digit year, interpreted as > 1960 by default (also accepts 4) | `14`                        |
| yyyy             |              | four-digit year                                                   | `2014`                      |
| yyyyy            |              | four- to six-digit years                                          | `10340`                     |
| yyyyyy           |              | six-digit years                                                   | `010340`                    |
| G                |              | abbreviated localized era                                         | `AD`                        |
| GG               |              | unabbreviated localized era                                       | `Anno Domini`               |
| GGGGG            |              | one-letter localized era                                          | `A`                         |
| kk               |              | ISO week year, unpadded                                           | `17`                        |
| kkkk             |              | ISO week year, padded to 4                                        | `2014`                      |
| W                |              | ISO week number, unpadded                                         | `32`                        |
| WW               |              | ISO week number, padded to 2                                      | `32`                        |
| o                |              | ordinal (day of year), unpadded                                   | `218`                       |
| ooo              |              | ordinal (day of year), padded to 3                                | `218`                       |
| q                |              | quarter, no padding                                               | `3`                         |
| D                |              | localized numeric date                                            | `9/6/2014`                  |
| DD               |              | localized date with abbreviated month                             | `Aug 6, 2014`               |
| DDD              |              | localized date with full month                                    | `August 6, 2014`            |
| DDDD             |              | localized date with full month and weekday                        | `Wednesday, August 6, 2014` |
| t                |              | localized time                                                    | `1:07 AM`                   |
| tt               |              | localized time with seconds                                       | `1:07:04 PM`                |
| T                |              | localized 24-hour time                                            | `13:07`                     |
| TT               |              | localized 24-hour time with seconds                               | `13:07:04`                  |
| f                |              | short localized date and time                                     | `8/6/2014, 1:07 PM`         |
| ff               |              | less short localized date and time                                | `Aug 6, 2014, 1:07 PM`      |
| F                |              | short localized date and time with seconds                        | `8/6/2014, 1:07:04 PM`      |
| FF               |              | less short localized date and time with seconds                   | `Aug 6, 2014, 1:07:04 PM`   |
| '                |              | literal start/end, characters between are not tokenized           | `'T'`                       |


================================================
FILE: docs/tour.md
================================================
# A quick tour

Luxon is a library that makes it easier to work with dates and times in JavaScript. If you want, add and subtract them, format and parse them, ask them hard questions, and so on, Luxon provides a much easier and comprehensive interface than the native types it wraps. We're going to talk about the most immediately useful subset of that interface.

This is going to be a bit brisk, but keep in mind that the API docs are comprehensive, so if you want to know more, feel free to [dive into them](https://moment.github.io/luxon/api-docs/index.html).

## Your first DateTime

The most important class in Luxon is `DateTime`. A DateTime represents a specific millisecond in time, along with a time zone and a locale. Here's one that represents May 15, 2017 at 8:30 in the morning:

```js
const dt = DateTime.local(2017, 5, 15, 8, 30);
```

[DateTime.local](../class/src/datetime.js~DateTime.html#static-method-local) takes any number of arguments, all the way out to milliseconds (months are 1-indexed). Underneath, this is similar to a JavaScript Date object. But we've decorated it with lots of useful methods.

## Creating a DateTime

There are lots of ways to create a DateTime by parsing strings or constructing them out of parts. You've already seen one, `DateTime.local()`, but let's talk about three more.

### Get the current date and time

To get the current time, just do this:

```js
const now = DateTime.now();
```

This is really the equivalent to calling `DateTime.local()` with no arguments, but it's a little clearer.

### Create from an object

The most powerful way to create a DateTime instance is to provide an object containing all the information:

```js
dt = DateTime.fromObject({day: 22, hour: 12 }, { zone: 'America/Los_Angeles', numberingSystem: 'beng'})
```

Don't worry too much about the properties you don't understand yet; the point is that you can set every attribute of a DateTime when you create it. One thing to notice from the example is that we just set the day and hour; the year and month get defaulted to the current one and the minutes, seconds, and milliseconds get defaulted to 0. So `DateTime.fromObject` is sort of the power user interface.

### Parse from ISO 8601

Luxon has lots of parsing capabilities, but the most important one is parsing [ISO 8601](https://en.wikipedia.org/wiki/ISO_8601) strings, because they're more-or-less the standard wire format for dates and times. Use `DateTime.fromISO`.


```js
DateTime.fromISO("2017-05-15")          //=> May 15, 2017 at midnight
DateTime.fromISO("2017-05-15T08:30:00") //=> May 15, 2017 at 8:30
```

You can parse a bunch of other formats, including [your own custom ones](parsing.md).

## Getting to know your DateTime instance

Now that we've made some DateTimes, let's see what we can ask of it.

### toString

The first thing we want to see is the DateTime as a string. Luxon returns ISO 8601 strings:

```js
DateTime.now().toString(); //=> '2017-09-14T03:20:34.091-04:00'
```

### Getting at components

We can get at the components of the time individually through getters. For example:

```js
dt = DateTime.now();
dt.year     //=> 2017
dt.month    //=> 9
dt.day      //=> 14
dt.second   //=> 47
dt.weekday  //=> 4
```

### Other fun accessors

```js
dt.zoneName     //=> 'America/New_York'
dt.offset       //=> -240
dt.daysInMonth  //=> 30
```

There are lots more!

## Formatting your DateTime

You may want to output your DateTime to a string for a machine or a human to read. Luxon has lots of tools for this, but two of them are most important. If you want to format a human-readable string, use `toLocaleString`:

```js
dt.toLocaleString()      //=> '9/14/2017'
dt.toLocaleString(DateTime.DATETIME_MED) //=> 'September 14, 3:21 AM'
```

This works well across different locales (languages) by letting the browser figure out what order the different parts go in and how to punctuate them.

If you want the string read by another program, you almost certainly want to use `toISO`:

```js
dt.toISO() //=> '2017-09-14T03:21:47.070-04:00'
```

Custom formats are also supported. See [formatting](formatting).

## Transforming your DateTime

### Immutability

Luxon objects are immutable. That means that you can't alter them in place, just create altered copies. Throughout the documentation, we use terms like "alter", "change", and "set" loosely, but rest assured we mean "create a new instance with different properties".

### Math

This is easier to show than to tell. All of these calls return new DateTime instances:

```js
var dt = DateTime.now();
dt.plus({ hours: 3, minutes: 2 });
dt.minus({ days: 7 });
dt.startOf('day');
dt.endOf('hour');
```

### Set

You can create new instances by overriding specific properties:

```js
var dt = DateTime.now();
dt.set({hour: 3}).hour   //=> 3
```

## Intl

Luxon provides several different Intl capabilities, but the most important one is in formatting:

```js
var dt = DateTime.now();
var f = {month: 'long', day: 'numeric'};
dt.setLocale('fr').toLocaleString(f)      //=> '14 septembre'
dt.setLocale('en-GB').toLocaleString(f)   //=> '14 September'
dt.setLocale('en-US').toLocaleString(f)  //=> 'September 14'
```

Luxon's Info class can also list months or weekdays for different locales:

```js
Info.months('long', {locale: 'fr'}) //=> [ 'janvier', 'février', 'mars', 'avril', ... ]
```

## Time zones

Luxon supports time zones. There's a whole [big section](zones) about it. But briefly, you can create DateTimes in specific zones and change their zones:

```js
DateTime.fromObject({}, {zone: 'America/Los_Angeles'}); // now, but expressed in LA's local time
DateTime.now().setZone("America/Los_Angeles"); // same
```

Luxon also supports UTC directly:

```js
DateTime.utc(2017, 5, 15);
DateTime.utc(); // now, in UTC time zone
DateTime.now().toUTC();
DateTime.utc().toLocal();
```

## Durations

The Duration class represents a quantity of time such as "2 hours and 7 minutes". You create them like this:

```js
var dur = Duration.fromObject({ hours: 2, minutes: 7 });
```

They can be added or subtracted from DateTimes like this:

```js
dt.plus(dur);
```

They have getters just like DateTime:

```js
dur.hours   //=> 2
dur.minutes //=> 7
dur.seconds //=> 0
```

And some other useful stuff:

```js
dur.as('seconds') //=> 7620
dur.toObject()    //=> { hours: 2, minutes: 7 }
dur.toISO()       //=> 'PT2H7M'
```

You can also format, negate, and normalize them. See it all in the `Duration` API docs.

## Intervals

Intervals are a specific period of time, such as "between now and midnight". They're really a wrapper for two DateTimes that form its endpoints. Here's what you can do with them:

```js
now = DateTime.now();
later = DateTime.local(2020, 10, 12);
i = Interval.fromDateTimes(now, later);

i.length()                             //=> 97098768468
i.length('years')                //=> 3.0762420239726027
i.contains(DateTime.local(2019))       //=> true

i.toISO()       //=> '2017-09-14T04:07:11.532-04:00/2020-10-12T00:00:00.000-04:00'
i.toString()    //=> '[2017-09-14T04:07:11.532-04:00 – 2020-10-12T00:00:00.000-04:00)
```

Note that Luxon's Intervals are always half-open, meaning the starting point is included in the interval while the end point is not.
The following code will not work as expected:
```js
const start = DateTime.now().startOf('day');
const end = start.endOf('day');
const i = Interval.fromDateTimes(start, end);

i.length('hours')    //=> 23.99999972222222
i.toString()         //=> [2025-07-09T00:00:00.000+02:00 – 2025-07-09T23:59:59.999+02:00)
```

This is because `endOf('day')` returns the last millisecond of the day and as a result that last millisecond is _not_
included in the interval.

`Interval.after` or `Interval.before` are better suited for creating Intervals of a specific length:
```js
const start = DateTime.now().startOf('day');
const i1 = Interval.after(start, { days: 1 });
const i2 = Interval.before(start, { days: 1 });

i1.length('hours')    //=> 24
i1.toString()         //=> [2025-07-09T00:00:00.000+02:00 – 2025-07-10T00:00:00.000+02:00)

i2.length('hours')    //=> 24
i2.toString()         //=> [2025-07-08T00:00:00.000+02:00 – 2025-07-09T00:00:00.000+02:00)
```

Intervals can be split up into smaller intervals, perform set-like operations with other intervals, and few other handy features. See the `Interval` API docs.


================================================
FILE: docs/upgrading.md
================================================
# Upgrading Luxon

## 2.x to 3.0

Version 3.0 has one breaking change: specifying "system" as the zone always results in the system zone, regardless of what you have the default set to. To get the default zone (whatever it is set to), use "default":

```js
Settings.defaultZone = "America/Chicago";

DateTime.now().setZone("default") // results in Chicago time
DateTime.now().setZone("system") // uses the user's system time
```

If this seems obvious, just be aware that it didn't work like that before!

## 1.x to 2.0

Version 2.0 of Luxon has a number of breaking changes.

### Environment support

Luxon 2.0 does not support Node < 12, or any version of IE. It also only supports newer versions of major browsers. This change
allows Luxon to make more assumptions about what's supported in the environment and will allow Luxon's code to simplify. See
the [Support Matrix](matrix.md) for more.

For this same reason, a polyfilled build is no longer provided; everything Luxon needs comes standard on browsers.

### Breaking signature changes

There are many more specific breaking changes. Most are aimed and making Luxon's handling of option parameters more consistent.

#### fromObject
`DateTime.fromObject()` and `Duration.fromObject()` now accept two parameters: one for the object and one for the options.

For example:

```js
// Luxon 1.x
DateTime.fromObject({ hour: 3, minute: 2, zone: "America/New_York", locale: "ru" });
Duration.fromObject({ hours: 3, minutes: 2, conversionAccuracy: "casual", locale: "ru" });

// vs Luxon 2.x
DateTime.fromObject({ hour: 3, minute: 2 }, { zone: "America/New_York", locale: "ru" });
Duration.fromObject({ hours: 3, minutes: 2 }, { conversionAccuracy: "casual", locale: "ru" });
```

#### toLocaleString

In Luxon 1.x, you can mix Intl options with overrides of the DateTime configuration into the same options parameter. These are now
two separate parameters:

```js

// Luxon 1.x
DateTime.now().toLocaleString({ hour: "2-digit", locale: "ru" })

// vs Luxon 2.x

DateTime.now().toLocaleString({ hour: "2-digit" }, { locale: "ru" })
```

#### System zone

The zone of the executing environment (e.g. the time set on the computer running the browser running Luxon), is now called
"system" instead of "local" to reduce confusion.

```js
DateTime.fromObject({}, { zone: "local" }) // still works
DateTime.fromObject({}, { zone: "system" }) // preferred

DateTime.fromObject({}, { zone: "system" }).zone // => type is SystemZone
DateTime.fromObject({}, { zone: "system" }).zone.type // => "system"
```

#### Default zone

Luxon 2.x cleans up the handling of `Settings.defaultZone`:

```js

// setting
Settings.defaultZone = "America/New_York"; // can take a string
Settings.defaultZone = IANAZone.create("America/New_York"); // or a Zone instance

// getting
Settings.defaultZone //=> a Zone instance
```

The most significant breaking change here is that `Settings.defaultZoneName` no longer exists.

#### Other breaking changes

 * `DateTime#toObject` no longer accepts an `includeConfig` option
 * `resolvedLocaleOpts` is now `resolvedLocaleOptions`
 * `Zone#universal` is now `Zone#isUniversal`

### Non-breaking changes

 * `DateTime.local()` and `DateTime.utc()` now take an options parameter for setting zone and locale, same as `fromObject()`.

### A note

We originally had more ambitious plans for Luxon 2.0: a port to Typescript, an overhaul of error handling, and lots of other changes.
The problem is that we're very busy, and in the meantime browsers have evolved quickly, the mistakes in our API bothered a lot
of developers, and our need to support old environments made Luxon more difficult to change. So we made a basic set of changes
to give us some operating room. And hopefully someday we'll get back to those more ambitious plans.


================================================
FILE: docs/validity.md
================================================
# Validity

## Invalid DateTimes

One of the most irritating aspects of programming with time is that it's possible to end up with invalid dates. This is a bit subtle: barring integer overflows, there's no count of milliseconds that don't correspond to a valid DateTime, but when working with calendar units, it's pretty easy to say something like "June 400th". Luxon considers that invalid and will mark it accordingly.

Unless you've asked Luxon to throw an exception when it creates an invalid DateTime (see more on that below), it will fail silently, creating an instance that doesn't know how to do anything. You can check validity with `isValid`:

```js
> var dt = DateTime.fromObject({ month: 6, day: 400 });
dt.isValid //=> false
```

All of the methods or getters that return primitives return degenerate ones:

```js
dt.year; //=>  NaN
dt.toString(); //=> 'Invalid DateTime'
dt.toObject(); //=> {}
```

Methods that return other Luxon objects will return invalid ones:

```js
dt.plus({ days: 4 }).isValid; //=> false
```

## Reasons a DateTimes can be invalid

The most common way to do that is to over- or underflow some unit:

- February 40th
- 28:00
- -4 pm
- etc

But there are other ways to do it:

```js
// specify a time zone that doesn't exist
DateTime.now().setZone("America/Blorp").isValid; //=> false

// provide contradictory information (here, this date is not a Wednesday)
DateTime.fromObject({ year: 2017, month: 5, day: 25, weekday: 3 }).isValid; //=> false
```

Note that some other kinds of mistakes throw, based on our judgment that they are more likely programmer errors than data issues:

```js
DateTime.now().set({ blorp: 7 }); //=> kerplosion
```

## Debugging invalid DateTimes

Because DateTimes fail silently, they can be a pain to debug. Luxon has some features that can help.

### invalidReason and invalidExplanation

Invalid DateTime objects are happy to tell you why they're invalid. `invalidReason` will give you a consistent error code you can use, whereas `invalidExplanation` will spell it out

```js
var dt = DateTime.now().setZone("America/Blorp");
dt.invalidReason; //=>  'unsupported zone'
dt.invalidExplanation; //=> 'the zone "America/Blorp" is not supported'
```

### throwOnInvalid

You can make Luxon throw whenever it creates an invalid DateTime. The message will combine `invalidReason` and `invalidExplanation`:

```js
Settings.throwOnInvalid = true;
DateTime.now().setZone("America/Blorp"); //=> Error: Invalid DateTime: unsupported zone: the zone "America/Blorp" is not supported
```

You can of course leave this on in production too, but be sure to try/catch it appropriately.

## Invalid Durations

Durations can be invalid too. The easiest way to get one is to diff an invalid DateTime.

```js
DateTime.local(2017, 28).diffNow().isValid; //=> false
```

## Invalid Intervals

Intervals can be invalid. This can happen a few different ways:

- The end time is before the start time
- It was created from invalid DateTime or Duration


================================================
FILE: docs/why.md
================================================
# Why does Luxon exist?

What's the deal with this whole Luxon thing anyway? Why did I write it? How is it related to the Moment project? What's different about it? This page tries to hash all that out.

## A disclaimer

I should clarify here that I'm just one of Moment's maintainers; I'm not in charge and I'm not Moment's creator. The opinions here are solely mine. Finally, none of this is meant to bash Moment, a project I've spent a lot of time on and whose other developers I respect.

## Origin

Luxon started because I had a bunch of ideas on how to improve Moment but kept finding Moment wasn't a good codebase to explore them with. Namely:

- I wanted to try out some ideas that I thought would provide a better, more explicit API but didn't want to break everything in Moment.
- I had an idea on how to provide out-of-the-box, no-data-files-required support for time zones, but Moment's design made that difficult.
- I wanted to completely rethink how internationalization worked by using the Intl API that comes packaged in browsers.
- I wanted to use a modern JS toolchain, which would require a major retrofit to Moment.

So I decided to write something from scratch, a sort of modernized Moment. It's a combination of all the things I learned maintaining Moment and Twix, plus a bunch of fresh ideas. I worked on it in little slivers of spare time for about two years. But now it's ready to actually use, and the Moment team likes it enough that we pulled it under the organization's umbrella.

## Ideas in Luxon

Luxon is built around a few core ideas:

1.  Keep the basic chainable date wrapper idea from Moment.
1.  Make all the types immutable.
1.  Make the API explicit; different methods do different things and have well-defined options.
1.  Use the Intl API to provide internationalization, including token parsing. Fall back to English if the browser doesn't support those APIs.
1.  Abuse the Intl API horribly to provide time zone support. Only possible for modern browsers.
1.  Provide more comprehensive duration support.
1.  Directly provide interval support.
1.  Write inline docs for everything.

These ideas have some big advantages:

1.  It's much easier to understand and debug code that uses Luxon.
1.  Using native browser capabilities for internationalization leads to a much better behavior and is dramatically easier to maintain.
1.  Luxon has the best time zone support of any JS date library.
1.  Luxon's durations are both flexible and easy to use.
1.  The documentation is very good.

They also have some disadvantages:

1.  Using modern browser capabilities means that the fallback behavior introduces complexity for the programmer.
1.  Never keeping internationalized strings in the code base means that some capabilities have to wait until the browsers provide it.
1.  Some aspects of the Intl API are browser-dependent, which means Luxon's behavior is too.

## Place in the Moment project

Luxon lives in the Moment project because, basically, we all really like it, and it represents a huge improvement.

But Luxon doesn't quite fulfill Moment's mandate. Since it sometimes relies on browsers' implementations of the `Intl` specifications, it doesn't provide some of Moment's most commonly-used features on all browsers. Relative date formatting is for instance not supported in IE11 and [other older browsers](https://caniuse.com/?search=Intl%20RelativeTimeFormat). Luxon's Intl features do not work as expected on sufficiently outdated browsers, whereas Moment's all work everywhere. That represents a good tradeoff, IMO, but it's clearly a different one than Moment makes.

Luxon makes a major break in API conventions. Part of Moment's charm is that you just call `moment()` on basically anything and you get date, whereas Luxon forces you to decide that you want to call `fromISO` or whatever. The upshot of all that is that Luxon feels like a different library; that's why it's not Moment 3.0.

So what is it then? We're not really sure. We're calling it a Moment labs project. Will its ideas get backported into Moment 3? Will it gradually siphon users away from Moment and become the focus of the Moment project? Will the march of modern browsers retire the arguments above and cause us to revisit branding Luxon as Moment? We don't know.

There, now you know as much as I do.

## Future plans

Luxon is fully usable and I plan to support it indefinitely. It's also largely complete. Luxon will eventually strip out its fallbacks for missing platform features. But overall I expect the core functionality to stay basically as it is, adding mostly minor tweaks and bugfixes.


================================================
FILE: docs/zones.md
================================================
# Time zones and offsets

Luxon has support for time zones. This page explains how to use them.

## Don't worry!

You _usually_ don't need to worry about time zones. Your code runs on a computer with a particular time zone and everything will work consistently in that zone without you doing anything. It's when you want to do complicated stuff _across_ zones that you have to think about it. Even then, here are some pointers to help you avoid situations where you have to think carefully about time zones:

1.  Don't make servers think about _local_ times. Configure them to use UTC and write your server's code to work in UTC. Times can often be thought of as a simple count of epoch milliseconds; what you would call that time (e.g. 9:30) in what zone doesn't (again, often) matter.
2.  Communicate times between systems in ISO 8601, like `2017-05-15T13:30:34Z` where possible (it doesn't matter if you use Z or some local offset; the point is that it precisely identifies the millisecond on the global timeline).
3.  Where possible, only think of time zones as a formatting concern; your application ideally never knows that the time it's working with is called "9:00" until it's being rendered to the user.
4.  Barring 3, do as much manipulation of the time (say, adding an hour to the current time) in the client code that's already running in the time zone where the results will matter.

All those things will make it less likely you ever need to work explicitly with time zones and may also save you plenty of other headaches. But those aren't possible for some applications; you might need to work with times in zones other than the one the program is running in, for any number of reasons. And that's where Luxon's time zone support comes in.

## Terminology

Bear with me here. Time zones are a pain in the ass. Luxon has lots of tools to deal with them, but there's no getting around the fact that they're complicated. The terminology for time zones and offsets isn't well-established. But let's try to impose some order:

1.  An **offset** is a difference between the local time and the UTC time, such as +5 (hours) or -12:30. They may be expressed directly in minutes, or in hours, or in a combination of minutes and hours. Here we'll use hours.
1.  A **time zone** is a set of rules, associated with a geographical location, that determines the local offset from UTC at any given time. The best way to identify a zone is by its IANA string, such as "America/New_York". That zone says something to the effect of "The offset is -5, except between March and November, when it's -4".
1.  A **fixed-offset time zone** is any time zone that never changes offsets, such as UTC. Luxon supports fixed-offset zones directly; they're specified like UTC+7, which you can interpret as "always with an offset of +7".
1.  A **named offset** is a time zone-specific name for an offset, such as Eastern Daylight Time. It expresses both the zone (America's EST roughly implies America/New_York) and the current offset (EST means -5). They are also confusing in that they overspecify the offset (e.g. for any given time it is unnecessary to specify EST vs EDT; it's always whichever one is right). They are also ambiguous (BST is both British Summer Time and Bangladesh Standard Time), unstandardized, and internationalized (what would a Frenchman call the US's EST?). For all these reasons, you should avoid them when specifying times programmatically. Luxon only supports their use in formatting.

Some subtleties:

1.  Multiple zones can have the same offset (think about the US's zones and their Canadian equivalents), though they might not have the same offset all the time, depending on when their DSTs are. Thus zones and offsets have a many-to-many relationship.
1.  Just because a time zone doesn't have a DST now doesn't mean it's fixed. Perhaps it had one in the past. Regardless, Luxon does not have first-class access to the list of rules, so it assumes any IANA-specified zone is not fixed and checks for its current offset programmatically.

If all this seems too terse, check out these articles. The terminology in them is subtly different but the concepts are the same:

- [Time Zones Aren’t Offsets – Offsets Aren’t Time Zones](https://spin.atomicobject.com/2016/07/06/time-zones-offsets/)
- [Stack Overflow's timezone wiki page](https://stackoverflow.com/tags/timezone/info)

## Luxon works with time zones

Luxon's DateTime class supports zones directly. By default, a date created in Luxon is "in" the local time zone of the machine it's running on. By "in" we mean that the DateTime has, as one of its properties, an associated zone.

It's important to remember that a DateTime represents a specific instant in time and that instant has an unambiguous meaning independent of what time zone you're in; the zone is really a piece of social metadata that affects how humans interact with the time, rather than a fact about the passing of time itself. Of course, Luxon is a library for humans, so that social metadata affects Luxon's behavior too. It just doesn't change _what time it is_.

Specifically, a DateTime's zone affects its behavior in these ways:

1.  Times will be formatted as they would be in that zone.
1.  Transformations to the DateTime (such as `plus` or `startOf`) will obey any DSTs in that zone that affect the calculation (see "Math across DSTs" below)

Generally speaking, Luxon does not support changing a DateTime's offset, just its zone. That allows it to enforce the behaviors in the list above. The offset for that DateTime is just whatever the zone says it is. If you are unconcerned with the effects above, then you can always give your DateTime a fixed-offset zone.

## Specifying a zone

Luxon's API methods that take a zone as an argument all let you specify the zone in a few ways.

| Type         | Example            | Description                                                       |
| ------------ | ------------------ | ----------------------------------------------------------------- |
| IANA         | 'America/New_York' | that zone                                                         |
| system       | 'system'           | the system's local zone                                           |
| default      | 'default'          | the default zone set by Settings.defaultZone                      |
| UTC          | 'utc'              | Universal Coordinated Time                                        |
| fixed offset | 'UTC+7'            | a fixed offset zone                                               |
| Zone         | new YourZone()     | A custom implementation of Luxon's Zone interface (advanced only) |

### IANA support

IANA-specified zones are string identifiers like "America/New_York" or "Asia/Tokyo". Luxon gains direct support for them by abusing built-in Intl APIs.

If you specify a zone and your environment doesn't support that zone, you'll get an [invalid](validity.md) DateTime. That could be because the environment doesn't support zones at all (generally browsers older than Luxon supports), because for whatever reason it doesn't support that _particular_ zone, or because the zone is just bogus. Like this:

```js
bogus = DateTime.local().setZone("America/Bogus");

bogus.isValid; //=> false
bogus.invalidReason; //=> 'unsupported zone'
```

## Creating DateTimes

### System zone by default

By default, DateTime instances are created in the system's local zone and parsed strings are interpreted as specifying times in the system's zone. For example, my computer is configured to use `America/New_York`, which has an offset of -4 in May:

```js
var local = DateTime.local(2017, 05, 15, 9, 10, 23);

local.zoneName; //=> 'America/New_York'
local.toString(); //=> '2017-05-15T09:10:23.000-04:00'

var iso = DateTime.fromISO("2017-05-15T09:10:23");

iso.zoneName; //=> 'America/New_York'
iso.toString(); //=> '2017-05-15T09:10:23.000-04:00'
```

### Creating DateTimes in a zone

Many of Luxon's factory methods allow you to tell it specifically what zone to create the DateTime in:

```js
var overrideZone = DateTime.fromISO("2017-05-15T09:10:23", { zone: "Europe/Paris" });

overrideZone.zoneName; //=> 'Europe/Paris'
overrideZone.toString(); //=> '2017-05-15T09:10:23.000+02:00'
```

Note two things:

1.  The date and time specified in the string was interpreted as a Parisian local time (i.e. it's the time that corresponds to what would be called 9:10 _there_).
2.  The resulting DateTime object is in Europe/Paris.

Those are conceptually independent (i.e. Luxon could have converted the time to the system zone), but in practice it's more convenient for the same option to govern both.

In addition, one static method, `utc()`, specifically interprets the input as being specified in UTC. It also returns a DateTime in UTC:

```js
var utc = DateTime.utc(2017, 05, 15, 9, 10, 23);

utc.zoneName; //=> 'UTC'
utc.toString(); //=> '2017-05-15T09:10:23.000Z'
```

### Strings that specify an offset

Some input strings may specify an offset as part of the string itself. In these cases, Luxon interprets the time as being specified with that offset, but converts the resulting DateTime into the system's local zone:

```js
var specifyOffset = DateTime.fromISO("2017-05-15T09:10:23-09:00");

specifyOffset.zoneName; //=> 'America/New_York'
specifyOffset.toString(); //=> '2017-05-15T14:10:23.000-04:00'

var specifyZone = DateTime.fromFormat(
  "2017-05-15T09:10:23 Europe/Paris",
  "yyyy-MM-dd'T'HH:mm:ss z"
);

specifyZone.zoneName; //=> 'America/New_York'
specifyZone.toString(); //=> '2017-05-15T03:10:23.000-04:00'
```

...unless a zone is specified as an option (see previous section), in which case the DateTime gets converted to _that_ zone:

```js
var specifyOffsetAndOverrideZone = DateTime.fromISO("2017-05-15T09:10:23-09:00", {
  zone: "Europe/Paris"
});

specifyOffsetAndOverrideZone.zoneName; //=> 'Europe/Paris'
specifyOffsetAndOverrideZone.toString(); //=> '2017-05-15T20:10:23.000+02:00'
```

### setZone

Finally, some parsing functions allow you to "keep" the zone in the string as the DateTime's zone. Note that if only an offset is provided by the string, the zone will be a fixed-offset one, since Luxon doesn't know which zone is meant, even if you do.

```js
var keepOffset = DateTime.fromISO("2017-05-15T09:10:23-09:00", { setZone: true });

keepOffset.zoneName; //=> 'UTC-9'
keepOffset.toString(); //=> '2017-05-15T09:10:23.000-09:00'

var keepZone = DateTime.fromFormat("2017-05-15T09:10:23 Europe/Paris", "yyyy-MM-dd'T'HH:mm:ss z", {
  setZone: true
});

keepZone.zoneName; //=> 'Europe/Paris'
keepZone.toString(); //=> '2017-05-15T09:10:23.000+02:00'
```

## Changing zones

### setZone

Luxon objects are immutable, so when we say "changing zones" we really mean "creating a new instance with a different zone". Changing zone generally means "change the zone in which this DateTime is expressed (and according to which rules it is manipulated), but don't change the underlying timestamp." For example:

```js
var local = DateTime.local();
var rezoned = local.setZone("America/Los_Angeles");

// different local times with different offsets
local.toString(); //=> '2017-09-13T18:30:51.141-04:00'
rezoned.toString(); //=> '2017-09-13T15:30:51.141-07:00'

// but actually the same time
local.valueOf() === rezoned.valueOf(); //=> true
```

### keepLocalTime

Generally, it's best to think of the zone as a sort of metadata that you slide around independent of the underlying count of milliseconds. However, sometimes that's not what you want. Sometimes you want to change zones while keeping the local time fixed and instead altering the timestamp. Luxon supports this:

```js
var local = DateTime.local();
var rezoned = local.setZone("America/Los_Angeles", { keepLocalTime: true });

local.toString(); //=> '2017-09-13T18:36:23.187-04:00'
rezoned.toString(); //=> '2017-09-13T18:36:23.187-07:00'

local.valueOf() === rezoned.valueOf(); //=> false
```

If you find that confusing, I recommend just not using it. On the other hand, if you find yourself using this all the time, you are probably doing something wrong.

## Accessors

Luxon DateTimes have a few different accessors that let you find out about the zone and offset:

```js
var dt = DateTime.local();

dt.zoneName; //=> 'America/New_York'
dt.offset; //=> -240
dt.offsetNameShort; //=> 'EDT'
dt.offsetNameLong; //=> 'Eastern Daylight Time'
dt.isOffsetFixed; //=> false
dt.isInDST; //=> true
```

Those are all documented in the [DateTime API docs](https://moment.github.io/luxon/api-docs/index.html#datetime).

## DST weirdness

Because our ancestors were morons, they opted for a system wherein many governments shift around the local time twice a year for no good reason. And it's not like they do it in a neat, coordinated fashion. No, they do it whimsically, varying the shifts' timing from country to country (or region to region!) and from year to year. And of course, they do it the opposite way south of the Equator. This is all a tremendous waste of everyone's energy and, er, time, but it is how the world works and a date and time library has to deal with it.

Most of the time, DST shifts will happen without you having to do anything about it and everything will just work. Luxon goes to some pains to make DSTs as unweird as possible. But there are exceptions. This section covers them.

### Invalid times

Some local times simply don't exist. The Spring Forward DST shift involves shifting the local time forward by (usually) one hour. In my zone, `America/New_York`, on March 12, 2017 the millisecond after `1:59:59.999` is `3:00:00.000`. Thus the times between `2:00:00.000` and `2:59:59.999`, inclusive, don't exist in that zone. But of course, nothing stops a user from constructing a DateTime out of that local time.

If you create such a DateTime from scratch, the missing time will be advanced by an hour:

```js
DateTime.local(2017, 3, 12, 2, 30).toString(); //=> '2017-03-12T03:30:00.000-04:00'
```

You can also do date math that lands you in the middle of the shift. These also push forward:

```js
DateTime.local(2017, 3, 11, 2, 30)
  .plus({ days: 1 })
  .toString(); //=> '2017-03-12T03:30:00.000-04:00'
DateTime.local(2017, 3, 13, 2, 30)
  .minus({ days: 1 })
  .toString(); //=> '2017-03-12T03:30:00.000-04:00'
```

### Ambiguous times

Harder to handle are ambiguous times. During Fall Back, some local times happen twice. In my zone, `America/New_York`, on November 5, 2017 the millisecond after `1:59:59.999` became `1:00:00.000`. But of course there was already a 1:00 that day, one hour before this one. So if you create a DateTime with a local time of 1:30, which time do you mean? It's an important question, because they correspond to different moments in time.

However, Luxon's behavior here is undefined. It makes no promises about which of the two possible timestamps the instance will represent. Currently, its specific behavior is like this:

```js
DateTime.local(2017, 11, 5, 1, 30).offset / 60; //=> -4
DateTime.local(2017, 11, 4, 1, 30).plus({ days: 1 }).offset / 60; //=> -4
DateTime.local(2017, 11, 6, 1, 30).minus({ days: 1 }).offset / 60; //=> -5
```

In other words, sometimes it picks one and sometimes the other. Luxon doesn't guarantee the specific behavior above. That's just what it happens to do.

If you're curious, this lack of definition is because Luxon doesn't actually know that any particular DateTime is an ambiguous time. It doesn't know the time zones rules at all. It just knows the local time does not contradict the offset and leaves it at that. To find out the time is ambiguous and define exact rules for how to resolve it, Luxon would have to test nearby times to see if it can find duplicate local time, and it would have to do that on every creation of a DateTime, regardless of whether it was anywhere near a real DST shift. Because that's onerous, Luxon doesn't bother.

### Math across DSTs

There's a whole [section](math.md) about date and time math, but it's worth highlighting one thing here: when Luxon does math across DSTs, it adjusts for them when working with higher-order, variable-length units like days, weeks, months, and years. When working with lower-order, exact units like hours, minutes, and seconds, it does not. For example, DSTs mean that days are not always the same length: one day a year is (usually) 23 hours long and another is 25 hours long. Luxon makes sure that adding days takes that into account. On the other hand, an hour is always 3,600,000 milliseconds.

An easy way to think of it is that if you add a day to a DateTime, you should always get the same time the next day, regardless of any intervening DSTs. On the other hand, adding 24 hours will result in DateTime that is 24 hours later, which may or may not be the same time the next day. In this example, my zone is `America/New_York`, which had a Spring Forward DST in the early hours of March 12.

```js
var start = DateTime.local(2017, 3, 11, 10);
start.hour; //=> 10, just for comparison
start.plus({ days: 1 }).hour; //=> 10, stayed the same
start.plus({ hours: 24 }).hour; //=> 11, DST pushed forward an hour
```

## Changing the default zone

By default, Luxon creates DateTimes in the system's zone. However, you can override this behavior globally:

```js
Settings.defaultZone = "Asia/Tokyo";
DateTime.local().zoneName; //=> 'Asia/Tokyo'

Settings.defaultZone = "utc";
DateTime.local().zoneName; //=> 'UTC'

// you can reset by setting to 'system'

Settings.defaultZone = "system";
DateTime.local().zoneName; //=> 'America/New_York'
```


================================================
FILE: jest.config.js
================================================
module.exports = {
  testEnvironment: "node",
  roots: ["test"],
  coverageDirectory: "build/coverage",
  collectCoverageFrom: ["src/**/*.js", "!src/zone.js"],
  transform: {
    "^.+\\.js$": "babel-jest",
  },
};


================================================
FILE: package.json
================================================
{
  "name": "luxon",
  "version": "3.7.2",
  "description": "Immutable date wrapper",
  "author": "Isaac Cambron",
  "keywords": [
    "date",
    "immutable"
  ],
  "repository": "https://github.com/moment/luxon",
  "exports": {
    ".": {
      "import": "./build/es6/luxon.mjs",
      "require": "./build/node/luxon.js"
    },
    "./package.json": "./package.json"
  },
  "scripts": {
    "build": "babel-node tasks/buildAll.js",
    "build-node": "babel-node tasks/buildNode.js",
    "build-global": "babel-node tasks/buildGlobal.js",
    "jest": "jest",
    "test": "jest --coverage",
    "api-docs": "mkdir -p build && documentation build src/luxon.js -f html -o build/api-docs && sed -i.bak 's/<\\/body>/<script src=\"\\..\\/global\\/luxon.js\"><\\/script><script>console.log(\"You can try Luxon right here using the `luxon` global, like `luxon.DateTime.now()`\");<\\/script><\\/body>/g' build/api-docs/index.html && rm build/api-docs/index.html.bak",
    "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": "node benchmarks/index.js",
    "codecov": "codecov",
    "prepack": "babel-node tasks/buildAll.js",
    "prepare": "husky install",
    "show-site": "http-server build"
  },
  "lint-staged": {
    "*.{js,json}": [
      "prettier --write"
    ]
  },
  "devDependencies": {
    "@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": "latest",
    "documentation": "latest",
    "fs-extra": "^6.0.1",
    "http-server": "^14.1.1",
    "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"
  },
  "main": "build/node/luxon.js",
  "module": "src/luxon.js",
  "browser": "build/cjs-browser/luxon.js",
  "jsdelivr": "build/global/luxon.min.js",
  "unpkg": "build/global/luxon.min.js",
  "engines": {
    "node": ">=12"
  },
  "files": [
    "build/node/luxon.js",
    "build/node/luxon.js.map",
    "build/cjs-browser/luxon.js",
    "build/cjs-browser/luxon.js.map",
    "build/amd/luxon.js",
    "build/amd/luxon.js.map",
    "build/global/luxon.js",
    "build/global/luxon.js.map",
    "build/global/luxon.min.js",
    "build/global/luxon.min.js.map",
    "build/es6/luxon.mjs",
    "build/es6/luxon.mjs.map",
    "src"
  ],
  "license": "MIT",
  "sideEffects": false
}


================================================
FILE: scripts/bootstrap.js
================================================
const luxon = require("../build/node/luxon");
global.DateTime = luxon.DateTime;
global.Duration = luxon.Duration;
global.Interval = luxon.Interval;
global.Settings = luxon.Settings;
global.Info = luxon.Info;
global.IANAZone = luxon.IANAZone;


================================================
FILE: scripts/deploy-site
================================================
#!/usr/bin/env bash
set -o errexit #abort if any command fails
me=$(basename "$0")

help_message="\
Usage: $me [-c FILE] [<options>]
Deploy generated files to a git branch.
Options:
  -h, --help               Show this help information.
  -v, --verbose            Increase verbosity. Useful for debugging.
  -e, --allow-empty        Allow deployment of an empty directory.
  -m, --message MESSAGE    Specify the message used when committing on the
                           deploy branch.
  -n, --no-hash            Don't append the source commit's hash to the deploy
                           commit's message.
  -c, --config-file PATH   Override default & environment variables' values
                           with those in set in the file at 'PATH'. Must be the
                           first option specified.
Variables:
  GIT_DEPLOY_DIR      Folder path containing the files to deploy.
  GIT_DEPLOY_BRANCH   Commit deployable files to this branch.
  GIT_DEPLOY_REPO     Push the deploy branch to this repository.
These variables have default values defined in the script. The defaults can be
overridden by environment variables. Any environment variables are overridden
by values set in a '.env' file (if it exists), and in turn by those set in a
file specified by the '--config-file' option."

parse_args() {
	# Set args from a local environment file.
	if [ -e ".env" ]; then
		source .env
	fi

	# Set args from file specified on the command-line.
	if [[ $1 = "-c" || $1 = "--config-file" ]]; then
		source "$2"
		shift 2
	fi

	# Parse arg flags
	# If something is exposed as an environment variable, set/overwrite it
	# here. Otherwise, set/overwrite the internal variable instead.
	while : ; do
		if [[ $1 = "-h" || $1 = "--help" ]]; then
			echo "$help_message"
			return 0
		elif [[ $1 = "-v" || $1 = "--verbose" ]]; then
			verbose=true
			shift
		elif [[ $1 = "-e" || $1 = "--allow-empty" ]]; then
			allow_empty=true
			shift
		elif [[ ( $1 = "-m" || $1 = "--message" ) && -n $2 ]]; then
			commit_message=$2
			shift 2
		elif [[ $1 = "-n" || $1 = "--no-hash" ]]; then
			GIT_DEPLOY_APPEND_HASH=false
			shift
		else
			break
		fi
	done

	# Set internal option vars from the environment and arg flags. All internal
	# vars should be declared here, with sane defaults if applicable.

	# Source directory & target branch.
	deploy_directory=${GIT_DEPLOY_DIR:-build}
	deploy_branch=${GIT_DEPLOY_BRANCH:-gh-pages}

	#if no user identity is already set in the current git environment, use this:
	default_username=${GIT_DEPLOY_USERNAME:-deploy.sh}
	default_email=${GIT_DEPLOY_EMAIL:-}

	#repository to deploy to. must be readable and writable.
	repo=${GIT_DEPLOY_REPO:-origin}

	#append commit hash to the end of message by default
	append_hash=${GIT_DEPLOY_APPEND_HASH:-true}
}

main() {
	parse_args "$@"

	enable_expanded_output

	if ! git diff --exit-code --quiet --cached; then
		echo Aborting due to uncommitted changes in the index >&2
		return 1
	fi

	commit_title=`git log -n 1 --format="%s" HEAD`
	commit_hash=` git log -n 1 --format="%H" HEAD`

	#default commit message uses last title if a custom one is not supplied
	if [[ -z $commit_message ]]; then
		commit_message="publish: $commit_title"
	fi

	#append hash to commit message unless no hash flag was found
	if [ $append_hash = true ]; then
		commit_message="$commit_message"$'\n\n'"generated from commit $commit_hash"
	fi

	previous_branch=`git rev-parse --abbrev-ref HEAD`

	if [ ! -d "$deploy_directory" ]; then
		echo "Deploy directory '$deploy_directory' does not exist. Aborting." >&2
		return 1
	fi

	# must use short form of flag in ls for compatibility with OS X and BSD
	if [[ -z `ls -A "$deploy_directory" 2> /dev/null` && -z $allow_empty ]]; then
		echo "Deploy directory '$deploy_directory' is empty. Aborting. If you're sure you want to deploy an empty tree, use the --allow-empty / -e flag." >&2
		return 1
	fi

	if git ls-remote --exit-code $repo "refs/heads/$deploy_branch" ; then
		# deploy_branch exists in $repo; make sure we have the latest version

		disable_expanded_output
		git fetch --force $repo $deploy_branch:$deploy_branch
		enable_expanded_output
	fi

	# check if deploy_branch exists locally
	if git show-ref --verify --quiet "refs/heads/$deploy_branch"
	then incremental_deploy
	else initial_deploy
	fi

	restore_head
}

initial_deploy() {
	git --work-tree "$deploy_directory" checkout --orphan $deploy_branch
	git --work-tree "$deploy_directory" add --all
	commit+push
}

incremental_deploy() {
	#make deploy_branch the current branch
	git symbolic-ref HEAD refs/heads/$deploy_branch
	#put the previously committed contents of deploy_branch into the index
	git --work-tree "$deploy_directory" reset --mixed --quiet
	git --work-tree "$deploy_directory" add --all

	set +o errexit
	diff=$(git --work-tree "$deploy_directory" diff --exit-code --quiet HEAD --)$?
	set -o errexit
	case $diff in
		0) echo No changes to files in $deploy_directory. Skipping commit.;;
		1) commit+push;;
		*)
			echo git diff exited with code $diff. Aborting. Staying on branch $deploy_branch so you can debug. To switch back to master, use: git symbolic-ref HEAD refs/heads/master && git reset --mixed >&2
			return $diff
			;;
	esac
}

commit+push() {
	set_user_id
	git --work-tree "$deploy_directory" commit -m "$commit_message"

	disable_expanded_output
	#--quiet is important here to avoid outputting the repo URL, which may contain a secret token
	git push --quiet $repo $deploy_branch
	enable_expanded_output
}

#echo expanded commands as they are executed (for debugging)
enable_expanded_output() {
	if [ $verbose ]; then
		set -o xtrace
		set +o verbose
	fi
}

#this is used to avoid outputting the repo URL, which may contain a secret token
disable_expanded_output() {
	if [ $verbose ]; then
		set +o xtrace
		set -o verbose
	fi
}

set_user_id() {
	if [[ -z `git config user.name` ]]; then
		git config user.name "$default_username"
	fi
	if [[ -z `git config user.email` ]]; then
		git config user.email "$default_email"
	fi
}

restore_head() {
	if [[ $previous_branch = "HEAD" ]]; then
		#we weren't on any branch before, so just set HEAD back to the commit it was on
		git update-ref --no-deref HEAD $commit_hash $deploy_branch
	else
		git symbolic-ref HEAD refs/heads/$previous_branch
	fi

	git reset --mixed
}

filter() {
	sed -e "s|$repo|\$repo|g"
}

sanitize() {
	"$@" 2> >(filter 1>&2) | filter
}

[[ $1 = --source-only ]] || main "$@"

================================================
FILE: scripts/jest
================================================
TZ="America/New_York" NODE_ICU_DATA="$(pwd)/node_modules/full-icu" LANG=en_US.utf8 jest $@

================================================
FILE: scripts/readme.md
================================================
These are scripts useful for development:

 1. `test` is a script for more conveniently running the tests if you've installed `full-icu` as an npm module
 1. `release`, `tag`, and `deploy-site` are administrative tasks you won't need


================================================
FILE: scripts/release
================================================
#!/usr/bin/env bash
./scripts/version || exit $?

npm run build
npm run site
npm publish
./scripts/tag
./scripts/deploy-site

================================================
FILE: scripts/repl
================================================
#!/bin/bash
LANG=en-US.utf8 node -i -r "./scripts/bootstrap.js"


================================================
FILE: scripts/tag
================================================
#!/usr/bin/env bash
./scripts/version || exit $?

PACKAGE_VERSION=$(node -p "require('./package.json').version")

git tag $PACKAGE_VERSION
git push origin master $PACKAGE_VERSION


================================================
FILE: scripts/test
================================================
#!/usr/bin/env bash
TZ="America/New_York" LANG=en_US.utf8 npm run test

================================================
FILE: scripts/version
================================================
#!/usr/bin/env bash

abort() {
  echo "ERROR: $1"
  exit 1
}

if [[ -x $(which ggrep) ]]
then
  grepper='ggrep'
else
  grepper='grep'
fi

PACKAGE_VERSION=$(node -p "require('./package.json').version")
PACKAGE_LOCK_VERSION=$(node -p "require('./package-lock.json').version")
MODULE_VERSION=$(node -p "require('./src/package.json').version")
EXPORTED_VERSION=$($grepper -oP "(?<=const VERSION = \").*(?=\";)" ./src/luxon.js)

if [ $PACKAGE_VERSION != $PACKAGE_LOCK_VERSION ]; then
  abort "package-lock.json's version differs from package.json's"
elif [ $PACKAGE_VERSION != $EXPORTED_VERSION ]; then
  abort "exported version differs from package.json's"
elif [ $PACKAGE_VERSION != $MODULE_VERSION ]; then
  abort "src/package.json differs from package.json's"
elif [ $(git tag -l "$PACKAGE_VERSION") ]; then
  abort "tag already exists"
fi


================================================
FILE: site/.nojekyll
================================================


================================================
FILE: site/demo/demo.css
================================================
.divider {
  color: blue;
}

.code {
  display: inline-block;
  font-family: monospace;
}

.result {
  color: darkgreen;
  font-style: italic;
}


================================================
FILE: site/demo/demo.js
================================================
function demo(luxon) {
  const DateTime = luxon.DateTime;
  const Duration = luxon.Duration;
  const Info = luxon.Info;

  const run = function (code) {
    let result;
    try {
      result = eval(code);
    } catch (e) {
      console.error(e);
      return "[error]";
    }

    switch (true) {
      case result.isValid === false:
        return "Invalid";
      case result instanceof DateTime:
        return "[ DateTime " + result.toISO() + " ]";
      case result instanceof Duration:
        return "[ Duration " + JSON.stringify(result.toObject()) + " ]";
      case result instanceof Date:
        return "[ Date " + result.toString() + " ]";
      default:
        return JSON.stringify(result);
    }
  };

  const examples = [];
  const example = function (code) {
    examples.push(
      "<tr class='example'><td class='code'>" +
        code +
        "</td><td class='divider'>//=> </td><td class='result'>" +
        run(code) +
        "</td></tr>"
    );
  };

  example("Info.features()");
  example("DateTime.now()");
  example("DateTime.now().toUnixInteger()");
  example("DateTime.now().toJSDate()");
  example("DateTime.utc().toISO()");
  example("DateTime.utc(2017, 5, 15, 17, 36)");
  example("DateTime.utc(2017, 5, 15, 17, 36).toLocal()");
  example("DateTime.local(2017, 5, 15, 17, 36)");
  example("DateTime.local(2017, 5, 15, 17, 36).toUTC()");
  example("DateTime.now().toObject()");
  example("DateTime.fromObject({ year: 2017, month: 5, day: 15, hour: 17, minute: 36 })");
  example(
    "DateTime.fromObject({ year: 2017, month: 5, day: 15, hour: 17, minute: 36 }, { zone: 'America/New_York' })"
  );
  example(
    "DateTime.fromObject({ year: 2017, month: 5, day: 15, hour: 17, minute: 36 }, { zone: 'Asia/Singapore' })"
  );
  example("DateTime.now().setZone('America/New_York')");
  example("DateTime.now().setZone('America/New_York').startOf('day')");
  example("DateTime.now().plus({minutes: 15, seconds: 8})");
  example("DateTime.now().plus({days: 6})");
  example("DateTime.now().minus({days: 6})");
  example("DateTime.now().diff(DateTime.local(1982, 5, 25)).milliseconds");
  example("DateTime.now().diff(DateTime.local(1982, 5, 25), 'days').days");
  example("DateTime.now().diff(DateTime.local(1982, 5, 25), ['days', 'hours'])");
  example("DateTime.now().toLocaleString()");
  example("DateTime.now().setLocale('zh').toLocaleString()");
  example("DateTime.now().toLocaleString(DateTime.DATE_MED)");
  example("DateTime.now().setLocale('zh').toLocaleString(DateTime.DATE_MED)");
  example("DateTime.now().setLocale('fr').toLocaleString(DateTime.DATE_FULL)");
  example("DateTime.fromISO('2017-05-15')");
  example("DateTime.fromISO('2017-05-15T17:36')");
  example("DateTime.fromISO('2017-W33-4')");
  example("DateTime.fromISO('2017-W33-4T04:45:32.343')");
  example("DateTime.fromFormat('12-16-2017', 'MM-dd-yyyy')");
  example("DateTime.now().toFormat('MM-dd-yyyy')");
  example("DateTime.now().toFormat('MMMM dd, yyyy')");
  example("DateTime.now().setLocale('fr').toFormat('MMMM dd, yyyy')");
  example("DateTime.fromFormat('May 25, 1982', 'MMMM dd, yyyy')");
  example("DateTime.fromFormat('mai 25, 1982', 'MMMM dd, yyyy', { locale: 'fr' })");
  example("DateTime.now().plus({ days: 1 }).toRelativeCalendar()");
  example("DateTime.now().plus({ days: -1 }).toRelativeCalendar()");
  example("DateTime.now().plus({ months: 1 }).toRelativeCalendar()");
  example("DateTime.now().setLocale('fr').plus({ days: 1 }).toRelativeCalendar()");
  example("DateTime.now().setLocale('fr').plus({ days: -1 }).toRelativeCalendar()");
  example("DateTime.now().setLocale('fr').plus({ months: 1 }).toRelativeCalendar()");

  let all = "<h1>Some Luxon examples</h1>";
  all +=
    "<p>This is not meant to be a comprehensive showcase of Luxon's capabilities, just a quick flavoring.</p>";
  all += "<table>";
  all += examples.join("");
  all += "</table>";

  document.body.innerHTML = all;
}

if (typeof define !== "undefined") {
  define(["luxon"], function (luxon) {
    return function () {
      demo(luxon);
    };
  });
} else {
  window.demo = demo;
}


================================================
FILE: site/demo/global.html
================================================
<!DOCTYPE html>
<html>
    <head>
        <link rel='stylesheet' href='demo.css'/>
        <script src='../global/luxon.js'></script>
        <script src='demo.js'></script>
        <script>document.addEventListener("DOMContentLoaded", function(){demo(window.luxon)});</script>
    </head>
</html>


================================================
FILE: site/demo/requirejs.html
================================================
<!DOCTYPE html>
<html>
    <head>
        <link rel='stylesheet' href='demo.css'/>
        <script src='https://cdnjs.cloudflare.com/ajax/libs/require.js/2.3.3/require.min.js'></script>
        <script>
            requirejs.config({
                paths: {
                    luxon: '../amd/luxon.min',
                }
            });
            requirejs(['demo'], function(demo) {
                demo();
            });
         </script>
    </head>
    <body>
    </body>
</html>


================================================
FILE: site/docs/_coverpage.md
================================================
![logo](_media/Luxon_icon_64x64.png)

# Luxon <small>3.x</small>

> A powerful, modern, and friendly wrapper for JavaScript dates and times.

 * DateTimes, Durations, and Intervals
 * Immutable, chainable, unambiguous API.
 * Native time zone and Intl support (no locale or tz files)

[GitHub](https://github.com/moment/luxon/)
[Get started](#Luxon)

![color](#e8dffc)


================================================
FILE: site/docs/_sidebar.md
================================================
* [Home](/)
* [Install guide](install.md)
* [A quick tour](tour.md)
* [Upgrade guide](upgrading.md)
* [Intl](intl.md)
* [Time zones and offsets](zones.md)
* [Calendars](calendars.md)
* [Formatting](formatting.md)
* [Parsing](parsing.md)
* [Math](math.md)
* [Validity](validity.md)
* [API docs](api-docs/index.html ':ignore')
* [Support matrix](matrix.md)
* [For Moment users](moment.md)
* [Why does Luxon exist?](why.md)



================================================
FILE: site/index.html
================================================
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>luxon - Immutable date wrapper</title>
  <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
  <meta name="description" content="Immutable date wrapper">
  <meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
  <link rel="stylesheet" href="https://unpkg.com/docsify/lib/themes/vue.css">
  <link rel="stylesheet" href="https://unpkg.com/docsify/lib/themes/dark.css">
  <link rel="stylesheet" href="plugins/dark-theme-toggle.css">
  <style>
    .dark .sidebar li {
      margin-right: 0;
    }
    .dark .cover.show {
      background-color: rgb(79 58 120) !important;
    }

    .dark .markdown-section p.tip, .dark .markdown-section tr:nth-child(2n) {
      background-color: #4c4c4c;
    }
  </style>
</head>
<body>
  <div id="app"></div>
  <script>
    window.$docsify = {
      search: 'auto',
      basePath: "docs/",
      name: "luxon",
      repo: "https://github.com/moment/luxon",
      homepage: "home.md",
      loadSidebar: true,
      subMaxLevel: 3,
      coverpage: true,
    }
  </script>
  <script src="https://unpkg.com/docsify/lib/docsify.min.js"></script>
  <script src="https://unpkg.com/docsify/lib/plugins/search.min.js"></script>
  <script src="plugins/dark-theme-toggle.js"></script>
  <script src="global/luxon.js"></script>
  <script>
    var DateTime = luxon.DateTime;
    console.log(
      "You can try Luxon right here using the `luxon` global, like `luxon.DateTime.now()`."
    );
  </script>
</body>
</html>


================================================
FILE: site/plugins/dark-theme-toggle.css
================================================
#docsify-dark-theme-toggle {
  position: absolute;
  display: inline-block;
  width: 52px;
  height: 28px;
  margin-left: 2rem;
  margin-top: 1.5rem;
  left: 0;
  top: 0;
  z-index: 0;
  cursor: pointer;
}
.sidebar > .app-name {
  position: relative;
}
.app-name > #docsify-dark-theme-toggle {
  margin-right: 1rem;
  margin-top: 0;
  right: 0;
  left: unset;
}
#docsify-dark-theme-toggle::before, #docsify-dark-theme-toggle::after {
  position: absolute;
  top: 0.1em;
  font-size: 16px;
  transition: opacity 0.3s;
}
#docsify-dark-theme-toggle::before {
  content: "🌙";
  left: 0.1em;
  opacity: 0;
  z-index: 1;
}
#docsify-dark-theme-toggle::after {
  content: "🌞";
  right: 0.1em;
  opacity: 1;
}
#docsify-dark-theme-toggle > span {
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  background-color: var(--theme-color, #42b983);
  border-radius: 28px;
  transition: background-color 0.3s;
}
#docsify-dark-theme-toggle > span::before {
  content: "";
  position: absolute;
  height: 22px;
  width: 22px;
  left: 3px;
  top: 3px;
  z-index: 1;
  background-color: white;
  border-radius: 50%;
  transition: transform 0.3s;
}
.dark #docsify-dark-theme-toggle::after {
  opacity: 0;
}
.dark #docsify-dark-theme-toggle::before {
  opacity: 1;
}
.dark #docsify-dark-theme-toggle > span {
  background-color: var(--theme-color, #ea6f5a);
}
.dark #docsify-dark-theme-toggle > span::before {
  transform: translateX(24px);
}

================================================
FILE: site/plugins/dark-theme-toggle.js
================================================
(() => {
  const darkThemeTogglePlugin = (hook, vm) => {
    const TOGGLE_ID = "docsify-dark-theme-toggle",
      dom = Docsify.dom,
      darkThemeStyleSheet = dom.find('link[href$="dark.css"]'),
      toggleEl = dom.create("div", "<span />"),
      applyTheme = (swap = false) => {
        const isDark = Boolean(swap ^ (localStorage[TOGGLE_ID] == "true"));
        localStorage[TOGGLE_ID] = isDark;
        darkThemeStyleSheet.disabled = !isDark;
        dom.toggleClass(dom.body, isDark ? "add" : "remove", "dark");
      };
    localStorage[TOGGLE_ID] ??= matchMedia("(prefers-color-scheme: dark)").matches;
    toggleEl.id = TOGGLE_ID;
    dom.on(toggleEl, "click", () => applyTheme(true));
    hook.init(applyTheme);
    hook.doneEach(() => dom.before(dom.find(".cover.show, .sidebar > .app-name"), toggleEl));
  };
  $docsify ??= {};
  $docsify.plugins = [...($docsify.plugins ?? []), darkThemeTogglePlugin];
})();


================================================
FILE: src/datetime.js
================================================
import Duration from "./duration.js";
import Interval from "./interval.js";
import Settings from "./settings.js";
import Info from "./info.js";
import Formatter from "./impl/formatter.js";
import FixedOffsetZone from "./zones/fixedOffsetZone.js";
import Locale from "./impl/locale.js";
import {
  isUndefined,
  maybeArray,
  isDate,
  isNumber,
  bestBy,
  daysInMonth,
  daysInYear,
  isLeapYear,
  weeksInWeekYear,
  normalizeObject,
  roundTo,
  objToLocalTS,
  padStart,
} from "./impl/util.js";
import { normalizeZone } from "./impl/zoneUtil.js";
import diff from "./impl/diff.js";
import { parseRFC2822Date, parseISODate, parseHTTPDate, parseSQL } from "./impl/regexParser.js";
import {
  parseFromTokens,
  explainFromTokens,
  formatOptsToTokens,
  expandMacroTokens,
  TokenParser,
} from "./impl/tokenParser.js";
import {
  gregorianToWeek,
  weekToGregorian,
  gregorianToOrdinal,
  ordinalToGregorian,
  hasInvalidGregorianData,
  hasInvalidWeekData,
  hasInvalidOrdinalData,
  hasInvalidTimeData,
  usesLocalWeekValues,
  isoWeekdayToLocal,
} from "./impl/conversions.js";
import * as Formats from "./impl/formats.js";
import {
  InvalidArgumentError,
  ConflictingSpecificationError,
  InvalidUnitError,
  InvalidDateTimeError,
} from "./errors.js";
import Invalid from "./impl/invalid.js";

const INVALID = "Invalid DateTime";
const MAX_DATE = 8.64e15;

function unsupportedZone(zone) {
  return new Invalid("unsupported zone", `the zone "${zone.name}" is not supported`);
}

// we cache week data on the DT object and this intermediates the cache
/**
 * @param {DateTime} dt
 */
function possiblyCachedWeekData(dt) {
  if (dt.weekData === null) {
    dt.weekData = gregorianToWeek(dt.c);
  }
  return dt.weekData;
}

/**
 * @param {DateTime} dt
 */
function possiblyCachedLocalWeekData(dt) {
  if (dt.localWeekData === null) {
    dt.localWeekData = gregorianToWeek(
      dt.c,
      dt.loc.getMinDaysInFirstWeek(),
      dt.loc.getStartOfWeek()
    );
  }
  return dt.localWeekData;
}

// clone really means, "make a new object with these modifications". all "setters" really use this
// to create a new object while only changing some of the properties
function clone(inst, alts) {
  const current = {
    ts: inst.ts,
    zone: inst.zone,
    c: inst.c,
    o: inst.o,
    loc: inst.loc,
    invalid: inst.invalid,
  };
  return new DateTime({ ...current, ...alts, old: current });
}

// find the right offset a given local time. The o input is our guess, which determines which
// offset we'll pick in ambiguous cases (e.g. there are two 3 AMs b/c Fallback DST)
function fixOffset(localTS, o, tz) {
  // Our UTC time is just a guess because our offset is just a guess
  let utcGuess = localTS - o * 60 * 1000;

  // Test whether the zone matches the offset for this ts
  const o2 = tz.offset(utcGuess);

  // If so, offset didn't change and we're done
  if (o === o2) {
    return [utcGuess, o];
  }

  // If not, change the ts by the difference in the offset
  utcGuess -= (o2 - o) * 60 * 1000;

  // If that gives us the local time we want, we're done
  const o3 = tz.offset(utcGuess);
  if (o2 === o3) {
    return [utcGuess, o2];
  }

  // If it's different, we're in a hole time. The offset has changed, but the we don't adjust the time
  return [localTS - Math.min(o2, o3) * 60 * 1000, Math.max(o2, o3)];
}

// convert an epoch timestamp into a calendar object with the given offset
function tsToObj(ts, offset) {
  ts += offset * 60 * 1000;

  const d = new Date(ts);

  return {
    year: d.getUTCFullYear(),
    month: d.getUTCMonth() + 1,
    day: d.getUTCDate(),
    hour: d.getUTCHours(),
    minute: d.getUTCMinutes(),
    second: d.getUTCSeconds(),
    millisecond: d.getUTCMilliseconds(),
  };
}

// convert a calendar object to a epoch timestamp
function objToTS(obj, offset, zone) {
  return fixOffset(objToLocalTS(obj), offset, zone);
}

// create a new DT instance by adding a duration, adjusting for DSTs
function adjustTime(inst, dur) {
  const oPre = inst.o,
    year = inst.c.year + Math.trunc(dur.years),
    month = inst.c.month + Math.trunc(dur.months) + Math.trunc(dur.quarters) * 3,
    c = {
      ...inst.c,
      year,
      month,
      day:
        Math.min(inst.c.day, daysInMonth(year, month)) +
        Math.trunc(dur.days) +
        Math.trunc(dur.weeks) * 7,
    },
    millisToAdd = Duration.fromObject({
      years: dur.years - Math.trunc(dur.years),
      quarters: dur.quarters - Math.trunc(dur.quarters),
      months: dur.months - Math.trunc(dur.months),
      weeks: dur.weeks - Math.trunc(dur.weeks),
      days: dur.days - Math.trunc(dur.days),
      hours: dur.hours,
      minutes: dur.minutes,
      seconds: dur.seconds,
      milliseconds: dur.milliseconds,
    }).as("milliseconds"),
    localTS = objToLocalTS(c);

  let [ts, o] = fixOffset(localTS, oPre, inst.zone);

  if (millisToAdd !== 0) {
    ts += millisToAdd;
    // that could have changed the offset by going over a DST, but we want to keep the ts the same
    o = inst.zone.offset(ts);
  }

  return { ts, o };
}

// helper useful in turning the results of parsing into real dates
// by handling the zone options
export function parseDataToDateTime(parsed, parsedZone, opts, format, text, specificOffset) {
  const { setZone, zone } = opts;
  if ((parsed && Object.keys(parsed).length !== 0) || parsedZone) {
    const interpretationZone = parsedZone || zone,
      inst = DateTime.fromObject(parsed, {
        ...opts,
        zone: interpretationZone,
        specificOffset,
      });
    return setZone ? inst : inst.setZone(zone);
  } else {
    return DateTime.invalid(
      new Invalid("unparsable", `the input "${text}" can't be parsed as ${format}`)
    );
  }
}

// if you want to output a technical format (e.g. RFC 2822), this helper
// helps handle the details
function toTechFormat(dt, format, allowZ = true) {
  return dt.isValid
    ? Formatter.create(Locale.create("en-US"), {
        allowZ,
        forceSimple: true,
      }).formatDateTimeFromString(dt, format)
    : null;
}

function toISODate(o, extended, precision) {
  const longFormat = o.c.year > 9999 || o.c.year < 0;
  let c = "";
  if (longFormat && o.c.year >= 0) c += "+";
  c += padStart(o.c.year, longFormat ? 6 : 4);
  if (precision === "year") return c;
  if (extended) {
    c += "-";
    c += padStart(o.c.month);
    if (precision === "month") return c;
    c += "-";
  } else {
    c += padStart(o.c.month);
    if (precision === "month") return c;
  }
  c += padStart(o.c.day);
  return c;
}

function toISOTime(
  o,
  extended,
  suppressSeconds,
  suppressMilliseconds,
  includeOffset,
  extendedZone,
  precision
) {
  let showSeconds = !suppressSeconds || o.c.millisecond !== 0 || o.c.second !== 0,
    c = "";
  switch (precision) {
    case "day":
    case "month":
    case "year":
      break;
    default:
      c += padStart(o.c.hour);
      if (precision === "hour") break;
      if (extended) {
        c += ":";
        c += padStart(o.c.minute);
        if (precision === "minute") break;
        if (showSeconds) {
          c += ":";
          c += padStart(o.c.second);
        }
      } else {
        c += padStart(o.c.minute);
        if (precision === "minute") break;
        if (showSeconds) {
          c += padStart(o.c.second);
        }
      }
      if (precision === "second") break;
      if (showSeconds && (!suppressMilliseconds || o.c.millisecond !== 0)) {
        c += ".";
        c += padStart(o.c.millisecond, 3);
      }
  }

  if (includeOffset) {
    if (o.isOffsetFixed && o.offset === 0 && !extendedZone) {
      c += "Z";
    } else if (o.o < 0) {
      c += "-";
      c += padStart(Math.trunc(-o.o / 60));
      if (extended) {
        c += ":";
      }
      c += padStart(Math.trunc(-o.o % 60));
    } else {
      c += "+";
      c += padStart(Math.trunc(o.o / 60));
      if (extended) {
        c += ":";
      }
      c += padStart(Math.trunc(o.o % 60));
    }
  }

  if (extendedZone) {
    c += "[" + o.zone.ianaName + "]";
  }
  return c;
}

// defaults for unspecified units in the supported calendars
const defaultUnitValues = {
    month: 1,
    day: 1,
    hour: 0,
    minute: 0,
    second: 0,
    millisecond: 0,
  },
  defaultWeekUnitValues = {
    weekNumber: 1,
    weekday: 1,
    hour: 0,
    minute: 0,
    second: 0,
    millisecond: 0,
  },
  defaultOrdinalUnitValues = {
    ordinal: 1,
    hour: 0,
    minute: 0,
    second: 0,
    millisecond: 0,
  };

// Units in the supported calendars, sorted by bigness
const orderedUnits = ["year", "month", "day", "hour", "minute", "second", "millisecond"],
  orderedWeekUnits = [
    "weekYear",
    "weekNumber",
    "weekday",
    "hour",
    "minute",
    "second",
    "millisecond",
  ],
  orderedOrdinalUnits = ["year", "ordinal", "hour", "minute", "second", "millisecond"];

// standardize case and plurality in units
function normalizeUnit(unit) {
  const normalized = {
    year: "year",
    years: "year",
    month: "month",
    months: "month",
    day: "day",
    days: "day",
    hour: "hour",
    hours: "hour",
    minute: "minute",
    minutes: "minute",
    quarter: "quarter",
    quarters: "quarter",
    second: "second",
    seconds: "second",
    millisecond: "millisecond",
    milliseconds: "millisecond",
    weekday: "weekday",
    weekdays: "weekday",
    weeknumber: "weekNumber",
    weeksnumber: "weekNumber",
    weeknumbers: "weekNumber",
    weekyear: "weekYear",
    weekyears: "weekYear",
    ordinal: "ordinal",
  }[unit.toLowerCase()];

  if (!normalized) throw new InvalidUnitError(unit);

  return normalized;
}

function normalizeUnitWithLocalWeeks(unit) {
  switch (unit.toLowerCase()) {
    case "localweekday":
    case "localweekdays":
      return "localWeekday";
    case "localweeknumber":
    case "localweeknumbers":
      return "localWeekNumber";
    case "localweekyear":
    case "localweekyears":
      return "localWeekYear";
    default:
      return normalizeUnit(unit);
  }
}

// cache offsets for zones based on the current timestamp when this function is
// first called. When we are handling a datetime from components like (year,
// month, day, hour) in a time zone, we need a guess about what the timezone
// offset is so that we can convert into a UTC timestamp. One way is to find the
// offset of now in the zone. The actual date may have a different offset (for
// example, if we handle a date in June while we're in December in a zone that
// observes DST), but we can check and adjust that.
//
// When handling many dates, calculating the offset for now every time is
// expensive. It's just a guess, so we can cache the offset to use even if we
// are right on a time change boundary (we'll just correct in the other
// direction). Using a timestamp from first read is a slight optimization for
// handling dates close to the current date, since those dates will usually be
// in the same offset (we could set the timestamp statically, instead). We use a
// single timestamp for all zones to make things a bit more predictable.
//
// This is safe for quickDT (used by local() and utc()) because we don't fill in
// higher-order units from tsNow (as we do in fromObject, this requires that
// offset is calculated from tsNow).
/**
 * @param {Zone} zone
 * @return {number}
 */
function guessOffsetForZone(zone) {
  if (zoneOffsetTs === undefined) {
    zoneOffsetTs = Settings.now();
  }

  // Do not cache anything but IANA zones, because it is not safe to do so.
  // Guessing an offset which is not present in the zone can cause wrong results from fixOffset
  if (zone.type !== "iana") {
    return zone.offset(zoneOffsetTs);
  }
  const zoneName = zone.name;
  let offsetGuess = zoneOffsetGuessCache.get(zoneName);
  if (offsetGuess === undefined) {
    offsetGuess = zone.offset(zoneOffsetTs);
    zoneOffsetGuessCache.set(zoneName, offsetGuess);
  }
  return offsetGuess;
}

// this is a dumbed down version of fromObject() that runs about 60% faster
// but doesn't do any validation, makes a bunch of assumptions about what units
// are present, and so on.
function quickDT(obj, opts) {
  const zone = normalizeZone(opts.zone, Settings.defaultZone);
  if (!zone.isValid) {
    return DateTime.invalid(unsupportedZone(zone));
  }

  const loc = Locale.fromObject(opts);

  let ts, o;

  // assume we have the higher-order units
  if (!isUndefined(obj.year)) {
    for (const u of orderedUnits) {
      if (isUndefined(obj[u])) {
        obj[u] = defaultUnitValues[u];
      }
    }

    const invalid = hasInvalidGregorianData(obj) || hasInvalidTimeData(obj);
    if (invalid) {
      return DateTime.invalid(invalid);
    }

    const offsetProvis = guessOffsetForZone(zone);
    [ts, o] = objToTS(obj, offsetProvis, zone);
  } else {
    ts = Settings.now();
  }

  return new DateTime({ ts, zone, loc, o });
}

function diffRelative(start, end, opts) {
  const round = isUndefined(opts.round) ? true : opts.round,
    rounding = isUndefined(opts.rounding) ? "trunc" : opts.rounding,
    format = (c, unit) => {
      c = roundTo(c, round || opts.calendary ? 0 : 2, opts.calendary ? "round" : rounding);
      const formatter = end.loc.clone(opts).relFormatter(opts);
      return formatter.format(c, unit);
    },
    differ = (unit) => {
      if (opts.calendary) {
        if (!end.hasSame(start, unit)) {
          return end.startOf(unit).diff(start.startOf(unit), unit).get(unit);
        } else return 0;
      } else {
        return end.diff(start, unit).get(unit);
      }
    };

  if (opts.unit) {
    return format(differ(opts.unit), opts.unit);
  }

  for (const unit of opts.units) {
    const count = differ(unit);
    if (Math.abs(count) >= 1) {
      return format(count, unit);
    }
  }
  return format(start > end ? -0 : 0, opts.units[opts.units.length - 1]);
}

function lastOpts(argList) {
  let opts = {},
    args;
  if (argList.length > 0 && typeof argList[argList.length - 1] === "object") {
    opts = argList[argList.length - 1];
    args = Array.from(argList).slice(0, argList.length - 1);
  } else {
    args = Array.from(argList);
  }
  return [opts, args];
}

/**
 * Timestamp to use for cached zone offset guesses (exposed for test)
 */
let zoneOffsetTs;
/**
 * Cache for zone offset guesses (exposed for test).
 
Download .txt
gitextract_l58zfrk8/

├── .agignore
├── .babelrc
├── .editorconfig
├── .gitattributes
├── .github/
│   ├── ISSUE_TEMPLATE/
│   │   ├── bug_report.md
│   │   └── feature_request.md
│   └── workflows/
│       └── test.yml
├── .gitignore
├── .husky/
│   ├── .gitignore
│   └── pre-commit
├── .prettierrc
├── CHANGELOG.md
├── CONTRIBUTING.md
├── LICENSE.md
├── README.md
├── babel.config.js
├── benchmarks/
│   ├── datetime.js
│   ├── index.js
│   ├── info.js
│   └── package.json
├── codecov.yml
├── docker/
│   ├── Dockerfile
│   ├── build
│   ├── npm
│   ├── push
│   └── readme.md
├── docs/
│   ├── calendars.md
│   ├── formatting.md
│   ├── home.md
│   ├── install.md
│   ├── intl.md
│   ├── math.md
│   ├── matrix.md
│   ├── moment.md
│   ├── parsing.md
│   ├── tour.md
│   ├── upgrading.md
│   ├── validity.md
│   ├── why.md
│   └── zones.md
├── jest.config.js
├── package.json
├── scripts/
│   ├── bootstrap.js
│   ├── deploy-site
│   ├── jest
│   ├── readme.md
│   ├── release
│   ├── repl
│   ├── tag
│   ├── test
│   └── version
├── site/
│   ├── .nojekyll
│   ├── demo/
│   │   ├── demo.css
│   │   ├── demo.js
│   │   ├── global.html
│   │   └── requirejs.html
│   ├── docs/
│   │   ├── _coverpage.md
│   │   └── _sidebar.md
│   ├── index.html
│   └── plugins/
│       ├── dark-theme-toggle.css
│       └── dark-theme-toggle.js
├── src/
│   ├── datetime.js
│   ├── duration.js
│   ├── errors.js
│   ├── impl/
│   │   ├── conversions.js
│   │   ├── diff.js
│   │   ├── digits.js
│   │   ├── english.js
│   │   ├── formats.js
│   │   ├── formatter.js
│   │   ├── invalid.js
│   │   ├── locale.js
│   │   ├── regexParser.js
│   │   ├── tokenParser.js
│   │   ├── util.js
│   │   └── zoneUtil.js
│   ├── info.js
│   ├── interval.js
│   ├── luxon.js
│   ├── package.json
│   ├── settings.js
│   ├── zone.js
│   └── zones/
│       ├── IANAZone.js
│       ├── fixedOffsetZone.js
│       ├── invalidZone.js
│       └── systemZone.js
├── tasks/
│   ├── build.js
│   ├── buildAll.js
│   ├── buildGlobal.js
│   └── buildNode.js
└── test/
    ├── datetime/
    │   ├── create.test.js
    │   ├── degrade.test.js
    │   ├── diff.test.js
    │   ├── dst.test.js
    │   ├── equality.test.js
    │   ├── format.test.js
    │   ├── getters.test.js
    │   ├── info.test.js
    │   ├── invalid.test.js
    │   ├── localeWeek.test.js
    │   ├── many.test.js
    │   ├── math.test.js
    │   ├── misc.test.js
    │   ├── proto.test.js
    │   ├── reconfigure.test.js
    │   ├── regexParse.test.js
    │   ├── relative.test.js
    │   ├── set.test.js
    │   ├── toFormat.test.js
    │   ├── tokenParse.test.js
    │   ├── transform.test.js
    │   ├── typecheck.test.js
    │   └── zone.test.js
    ├── duration/
    │   ├── accuracy.test.js
    │   ├── create.test.js
    │   ├── customMatrix.test.js
    │   ├── equality.test.js
    │   ├── format.test.js
    │   ├── getters.test.js
    │   ├── info.test.js
    │   ├── invalid.test.js
    │   ├── math.test.js
    │   ├── parse.test.js
    │   ├── proto.test.js
    │   ├── reconfigure.test.js
    │   ├── set.test.js
    │   ├── typecheck.test.js
    │   └── units.test.js
    ├── helpers.js
    ├── impl/
    │   └── english.test.js
    ├── info/
    │   ├── features.test.js
    │   ├── listers.test.js
    │   ├── localeWeek.test.js
    │   └── zones.test.js
    ├── interval/
    │   ├── create.test.js
    │   ├── format.test.js
    │   ├── getters.test.js
    │   ├── info.test.js
    │   ├── localeWeek.test.js
    │   ├── many.test.js
    │   ├── parse.test.js
    │   ├── proto.test.js
    │   ├── setter.test.js
    │   └── typecheck.test.js
    └── zones/
        ├── IANA.test.js
        ├── fixedOffset.test.js
        ├── invalid.test.js
        ├── local.test.js
        └── zoneInterface.test.js
Download .txt
SYMBOL INDEX (591 symbols across 33 files)

FILE: benchmarks/datetime.js
  function runDateTimeSuite (line 5) | function runDateTimeSuite() {

FILE: benchmarks/index.js
  function runAllSuites (line 6) | async function runAllSuites() {

FILE: benchmarks/info.js
  function runWeekdaysSuite (line 5) | function runWeekdaysSuite() {
  function runWeekdaysFormatSuite (line 30) | function runWeekdaysFormatSuite() {
  function runMonthsSuite (line 55) | function runMonthsSuite() {
  function runMonthsFormatSuite (line 79) | function runMonthsFormatSuite() {

FILE: site/demo/demo.js
  function demo (line 1) | function demo(luxon) {

FILE: src/datetime.js
  constant INVALID (line 54) | const INVALID = "Invalid DateTime";
  constant MAX_DATE (line 55) | const MAX_DATE = 8.64e15;
  function unsupportedZone (line 57) | function unsupportedZone(zone) {
  function possiblyCachedWeekData (line 65) | function possiblyCachedWeekData(dt) {
  function possiblyCachedLocalWeekData (line 75) | function possiblyCachedLocalWeekData(dt) {
  function clone (line 88) | function clone(inst, alts) {
  function fixOffset (line 102) | function fixOffset(localTS, o, tz) {
  function tsToObj (line 128) | function tsToObj(ts, offset) {
  function objToTS (line 145) | function objToTS(obj, offset, zone) {
  function adjustTime (line 150) | function adjustTime(inst, dur) {
  function parseDataToDateTime (line 189) | function parseDataToDateTime(parsed, parsedZone, opts, format, text, spe...
  function toTechFormat (line 208) | function toTechFormat(dt, format, allowZ = true) {
  function toISODate (line 217) | function toISODate(o, extended, precision) {
  function toISOTime (line 236) | function toISOTime(
  function normalizeUnit (line 342) | function normalizeUnit(unit) {
  function normalizeUnitWithLocalWeeks (line 375) | function normalizeUnitWithLocalWeeks(unit) {
  function guessOffsetForZone (line 414) | function guessOffsetForZone(zone) {
  function quickDT (line 436) | function quickDT(obj, opts) {
  function diffRelative (line 468) | function diffRelative(start, end, opts) {
  function lastOpts (line 499) | function lastOpts(argList) {
  class DateTime (line 543) | class DateTime {
    method constructor (line 547) | constructor(config) {
    method now (line 620) | static now() {
    method local (line 645) | static local() {
    method utc (line 676) | static utc() {
    method fromJSDate (line 691) | static fromJSDate(date, options = {}) {
    method fromMillis (line 720) | static fromMillis(milliseconds, options = {}) {
    method fromSeconds (line 748) | static fromSeconds(seconds, options = {}) {
    method fromObject (line 793) | static fromObject(obj, opts = {}) {
    method fromISO (line 920) | static fromISO(text, opts = {}) {
    method fromRFC2822 (line 940) | static fromRFC2822(text, opts = {}) {
    method fromHTTP (line 961) | static fromHTTP(text, opts = {}) {
    method fromFormat (line 980) | static fromFormat(text, fmt, opts = {}) {
    method fromString (line 1002) | static fromString(text, fmt, opts = {}) {
    method fromSQL (line 1027) | static fromSQL(text, opts = {}) {
    method invalid (line 1038) | static invalid(reason, explanation = null) {
    method isDateTime (line 1057) | static isDateTime(o) {
    method parseFormatForOpts (line 1067) | static parseFormatForOpts(formatOpts, localeOpts = {}) {
    method expandFormat (line 1079) | static expandFormat(fmt, localeOpts = {}) {
    method resetCache (line 1084) | static resetCache() {
    method get (line 1098) | get(unit) {
    method isValid (line 1108) | get isValid() {
    method invalidReason (line 1116) | get invalidReason() {
    method invalidExplanation (line 1124) | get invalidExplanation() {
    method locale (line 1133) | get locale() {
    method numberingSystem (line 1142) | get numberingSystem() {
    method outputCalendar (line 1151) | get outputCalendar() {
    method zone (line 1159) | get zone() {
    method zoneName (line 1167) | get zoneName() {
    method year (line 1176) | get year() {
    method quarter (line 1185) | get quarter() {
    method month (line 1194) | get month() {
    method day (line 1203) | get day() {
    method hour (line 1212) | get hour() {
    method minute (line 1221) | get minute() {
    method second (line 1230) | get second() {
    method millisecond (line 1239) | get millisecond() {
    method weekYear (line 1249) | get weekYear() {
    method weekNumber (line 1259) | get weekNumber() {
    method weekday (line 1270) | get weekday() {
    method isWeekend (line 1278) | get isWeekend() {
    method localWeekday (line 1288) | get localWeekday() {
    method localWeekNumber (line 1298) | get localWeekNumber() {
    method localWeekYear (line 1307) | get localWeekYear() {
    method ordinal (line 1316) | get ordinal() {
    method monthShort (line 1326) | get monthShort() {
    method monthLong (line 1336) | get monthLong() {
    method weekdayShort (line 1346) | get weekdayShort() {
    method weekdayLong (line 1356) | get weekdayLong() {
    method offset (line 1366) | get offset() {
    method offsetNameShort (line 1375) | get offsetNameShort() {
    method offsetNameLong (line 1391) | get offsetNameLong() {
    method isOffsetFixed (line 1406) | get isOffsetFixed() {
    method isInDST (line 1414) | get isInDST() {
    method getPossibleOffsets (line 1432) | getPossibleOffsets() {
    method isInLeapYear (line 1468) | get isInLeapYear() {
    method daysInMonth (line 1478) | get daysInMonth() {
    method daysInYear (line 1488) | get daysInYear() {
    method weeksInWeekYear (line 1499) | get weeksInWeekYear() {
    method weeksInLocalWeekYear (line 1509) | get weeksInLocalWeekYear() {
    method resolvedLocaleOptions (line 1525) | resolvedLocaleOptions(opts = {}) {
    method toUTC (line 1543) | toUTC(offset = 0, opts = {}) {
    method toLocal (line 1553) | toLocal() {
    method setZone (line 1566) | setZone(zone, { keepLocalTime = false, keepCalendarTime = false } = {}) {
    method reconfigure (line 1589) | reconfigure({ locale, numberingSystem, outputCalendar } = {}) {
    method setLocale (line 1600) | setLocale(locale) {
    method set (line 1617) | set(values) {
    method plus (line 1679) | plus(duration) {
    method minus (line 1691) | minus(duration) {
    method startOf (line 1709) | startOf(unit, { useLocaleWeeks = false } = {}) {
    method endOf (line 1773) | endOf(unit, opts) {
    method toFormat (line 1795) | toFormat(fmt, opts = {}) {
    method toLocaleString (line 1820) | toLocaleString(formatOpts = Formats.DATE_SHORT, opts = {}) {
    method toLocaleParts (line 1839) | toLocaleParts(opts = {}) {
    method toISO (line 1862) | toISO({
    method toISODate (line 1901) | toISODate({ format = "extended", precision = "day" } = {}) {
    method toISOWeekDate (line 1913) | toISOWeekDate() {
    method toISOTime (line 1934) | toISOTime({
    method toRFC2822 (line 1969) | toRFC2822() {
    method toHTTP (line 1981) | toHTTP() {
    method toSQLDate (line 1990) | toSQLDate() {
    method toSQLTime (line 2009) | toSQLTime({ includeOffset = true, includeZone = false, includeOffsetSp...
    method toSQL (line 2038) | toSQL(opts = {}) {
    method toString (line 2050) | toString() {
    method valueOf (line 2070) | valueOf() {
    method toMillis (line 2078) | toMillis() {
    method toSeconds (line 2086) | toSeconds() {
    method toUnixInteger (line 2094) | toUnixInteger() {
    method toJSON (line 2102) | toJSON() {
    method toBSON (line 2110) | toBSON() {
    method toObject (line 2121) | toObject(opts = {}) {
    method toJSDate (line 2138) | toJSDate() {
    method diff (line 2159) | diff(otherDateTime, unit = "milliseconds", opts = {}) {
    method diffNow (line 2183) | diffNow(unit = "milliseconds", opts = {}) {
    method until (line 2192) | until(otherDateTime) {
    method hasSame (line 2207) | hasSame(otherDateTime, unit, opts) {
    method equals (line 2224) | equals(other) {
    method toRelative (line 2253) | toRelative(options = {}) {
    method toRelativeCalendar (line 2284) | toRelativeCalendar(options = {}) {
    method min (line 2300) | static min(...dateTimes) {
    method max (line 2312) | static max(...dateTimes) {
    method fromFormatExplain (line 2328) | static fromFormatExplain(text, fmt, options = {}) {
    method fromStringExplain (line 2341) | static fromStringExplain(text, fmt, options = {}) {
    method buildFormatParser (line 2357) | static buildFormatParser(fmt, options = {}) {
    method fromFormatParser (line 2377) | static fromFormatParser(text, formatParser, opts = {}) {
    method DATE_SHORT (line 2419) | static get DATE_SHORT() {
    method DATE_MED (line 2427) | static get DATE_MED() {
    method DATE_MED_WITH_WEEKDAY (line 2435) | static get DATE_MED_WITH_WEEKDAY() {
    method DATE_FULL (line 2443) | static get DATE_FULL() {
    method DATE_HUGE (line 2451) | static get DATE_HUGE() {
    method TIME_SIMPLE (line 2459) | static get TIME_SIMPLE() {
    method TIME_WITH_SECONDS (line 2467) | static get TIME_WITH_SECONDS() {
    method TIME_WITH_SHORT_OFFSET (line 2475) | static get TIME_WITH_SHORT_OFFSET() {
    method TIME_WITH_LONG_OFFSET (line 2483) | static get TIME_WITH_LONG_OFFSET() {
    method TIME_24_SIMPLE (line 2491) | static get TIME_24_SIMPLE() {
    method TIME_24_WITH_SECONDS (line 2499) | static get TIME_24_WITH_SECONDS() {
    method TIME_24_WITH_SHORT_OFFSET (line 2507) | static get TIME_24_WITH_SHORT_OFFSET() {
    method TIME_24_WITH_LONG_OFFSET (line 2515) | static get TIME_24_WITH_LONG_OFFSET() {
    method DATETIME_SHORT (line 2523) | static get DATETIME_SHORT() {
    method DATETIME_SHORT_WITH_SECONDS (line 2531) | static get DATETIME_SHORT_WITH_SECONDS() {
    method DATETIME_MED (line 2539) | static get DATETIME_MED() {
    method DATETIME_MED_WITH_SECONDS (line 2547) | static get DATETIME_MED_WITH_SECONDS() {
    method DATETIME_MED_WITH_WEEKDAY (line 2555) | static get DATETIME_MED_WITH_WEEKDAY() {
    method DATETIME_FULL (line 2563) | static get DATETIME_FULL() {
    method DATETIME_FULL_WITH_SECONDS (line 2571) | static get DATETIME_FULL_WITH_SECONDS() {
    method DATETIME_HUGE (line 2579) | static get DATETIME_HUGE() {
    method DATETIME_HUGE_WITH_SECONDS (line 2587) | static get DATETIME_HUGE_WITH_SECONDS() {
  method [Symbol.for("nodejs.util.inspect.custom")] (line 2058) | [Symbol.for("nodejs.util.inspect.custom")]() {
  function friendlyDateTime (line 2595) | function friendlyDateTime(dateTimeish) {

FILE: src/duration.js
  constant INVALID (line 17) | const INVALID = "Invalid Duration";
  function clone (line 127) | function clone(dur, alts, clear = false) {
  function durationToMillis (line 138) | function durationToMillis(matrix, vals) {
  function normalizeValues (line 149) | function normalizeValues(matrix, vals) {
  function removeZeroes (line 202) | function removeZeroes(vals) {
  class Duration (line 225) | class Duration {
    method constructor (line 229) | constructor(config) {
    method fromMillis (line 272) | static fromMillis(count, opts) {
    method fromObject (line 296) | static fromObject(obj, opts = {}) {
    method fromDurationLike (line 323) | static fromDurationLike(durationLike) {
    method fromISO (line 351) | static fromISO(text, opts) {
    method fromISOTime (line 376) | static fromISOTime(text, opts) {
    method invalid (line 391) | static invalid(reason, explanation = null) {
    method normalizeUnit (line 408) | static normalizeUnit(unit) {
    method isDuration (line 440) | static isDuration(o) {
    method locale (line 448) | get locale() {
    method numberingSystem (line 457) | get numberingSystem() {
    method toFormat (line 487) | toFormat(fmt, opts = {}) {
    method toHuman (line 514) | toHuman(opts = {}) {
    method toObject (line 549) | toObject() {
    method toISO (line 564) | toISO() {
    method toISOTime (line 601) | toISOTime(opts = {}) {
    method toJSON (line 624) | toJSON() {
    method toString (line 632) | toString() {
    method toMillis (line 652) | toMillis() {
    method valueOf (line 662) | valueOf() {
    method plus (line 671) | plus(duration) {
    method minus (line 691) | minus(duration) {
    method mapUnits (line 705) | mapUnits(fn) {
    method get (line 722) | get(unit) {
    method set (line 733) | set(values) {
    method reconfigure (line 745) | reconfigure({ locale, numberingSystem, conversionAccuracy, matrix } = ...
    method as (line 759) | as(unit) {
    method normalize (line 778) | normalize() {
    method rescale (line 790) | rescale() {
    method shiftTo (line 801) | shiftTo(...units) {
    method shiftToAll (line 862) | shiftToAll() {
    method negate (line 881) | negate() {
    method removeZeros (line 895) | removeZeros() {
    method years (line 905) | get years() {
    method quarters (line 913) | get quarters() {
    method months (line 921) | get months() {
    method weeks (line 929) | get weeks() {
    method days (line 937) | get days() {
    method hours (line 945) | get hours() {
    method minutes (line 953) | get minutes() {
    method seconds (line 961) | get seconds() {
    method milliseconds (line 969) | get milliseconds() {
    method isValid (line 978) | get isValid() {
    method invalidReason (line 986) | get invalidReason() {
    method invalidExplanation (line 994) | get invalidExplanation() {
    method equals (line 1004) | equals(other) {
  method [Symbol.for("nodejs.util.inspect.custom")] (line 640) | [Symbol.for("nodejs.util.inspect.custom")]() {

FILE: src/errors.js
  class LuxonError (line 6) | class LuxonError extends Error {}
  class InvalidDateTimeError (line 11) | class InvalidDateTimeError extends LuxonError {
    method constructor (line 12) | constructor(reason) {
  class InvalidIntervalError (line 20) | class InvalidIntervalError extends LuxonError {
    method constructor (line 21) | constructor(reason) {
  class InvalidDurationError (line 29) | class InvalidDurationError extends LuxonError {
    method constructor (line 30) | constructor(reason) {
  class ConflictingSpecificationError (line 38) | class ConflictingSpecificationError extends LuxonError {}
  class InvalidUnitError (line 43) | class InvalidUnitError extends LuxonError {
    method constructor (line 44) | constructor(unit) {
  class InvalidArgumentError (line 52) | class InvalidArgumentError extends LuxonError {}
  class ZoneIsAbstractError (line 57) | class ZoneIsAbstractError extends LuxonError {
    method constructor (line 58) | constructor() {

FILE: src/impl/conversions.js
  function unitOutOfRange (line 17) | function unitOutOfRange(unit, value) {
  function dayOfWeek (line 24) | function dayOfWeek(year, month, day) {
  function computeOrdinal (line 36) | function computeOrdinal(year, month, day) {
  function uncomputeOrdinal (line 40) | function uncomputeOrdinal(year, ordinal) {
  function isoWeekdayToLocal (line 47) | function isoWeekdayToLocal(isoWeekday, startOfWeek) {
  function gregorianToWeek (line 55) | function gregorianToWeek(gregObj, minDaysInFirstWeek = 4, startOfWeek = ...
  function weekToGregorian (line 76) | function weekToGregorian(weekData, minDaysInFirstWeek = 4, startOfWeek =...
  function gregorianToOrdinal (line 98) | function gregorianToOrdinal(gregData) {
  function ordinalToGregorian (line 104) | function ordinalToGregorian(ordinalData) {
  function usesLocalWeekValues (line 116) | function usesLocalWeekValues(obj, loc) {
  function hasInvalidWeekData (line 145) | function hasInvalidWeekData(obj, minDaysInFirstWeek = 4, startOfWeek = 1) {
  function hasInvalidOrdinalData (line 163) | function hasInvalidOrdinalData(obj) {
  function hasInvalidGregorianData (line 174) | function hasInvalidGregorianData(obj) {
  function hasInvalidTimeData (line 188) | function hasInvalidTimeData(obj) {

FILE: src/impl/diff.js
  function dayDiff (line 3) | function dayDiff(earlier, later) {
  function highOrderDiffs (line 9) | function highOrderDiffs(cursor, later, units) {

FILE: src/impl/digits.js
  function parseDigits (line 49) | function parseDigits(str) {
  function resetDigitRegexCache (line 75) | function resetDigitRegexCache() {
  function digitRegex (line 79) | function digitRegex({ numberingSystem }, append = "") {

FILE: src/impl/english.js
  function stringify (line 4) | function stringify(obj) {
  function months (line 44) | function months(length) {
  function weekdays (line 75) | function weekdays(length) {
  function eras (line 98) | function eras(length) {
  function meridiemForDateTime (line 111) | function meridiemForDateTime(dt) {
  function weekdayForDateTime (line 115) | function weekdayForDateTime(dt, length) {
  function monthForDateTime (line 119) | function monthForDateTime(dt, length) {
  function eraForDateTime (line 123) | function eraForDateTime(dt, length) {
  function formatRelativeTime (line 127) | function formatRelativeTime(unit, count, numeric = "always", narrow = fa...
  function formatString (line 168) | function formatString(knownFormat) {

FILE: src/impl/formats.js
  constant DATE_SHORT (line 9) | const DATE_SHORT = {
  constant DATE_MED (line 15) | const DATE_MED = {
  constant DATE_MED_WITH_WEEKDAY (line 21) | const DATE_MED_WITH_WEEKDAY = {
  constant DATE_FULL (line 28) | const DATE_FULL = {
  constant DATE_HUGE (line 34) | const DATE_HUGE = {
  constant TIME_SIMPLE (line 41) | const TIME_SIMPLE = {
  constant TIME_WITH_SECONDS (line 46) | const TIME_WITH_SECONDS = {
  constant TIME_WITH_SHORT_OFFSET (line 52) | const TIME_WITH_SHORT_OFFSET = {
  constant TIME_WITH_LONG_OFFSET (line 59) | const TIME_WITH_LONG_OFFSET = {
  constant TIME_24_SIMPLE (line 66) | const TIME_24_SIMPLE = {
  constant TIME_24_WITH_SECONDS (line 72) | const TIME_24_WITH_SECONDS = {
  constant TIME_24_WITH_SHORT_OFFSET (line 79) | const TIME_24_WITH_SHORT_OFFSET = {
  constant TIME_24_WITH_LONG_OFFSET (line 87) | const TIME_24_WITH_LONG_OFFSET = {
  constant DATETIME_SHORT (line 95) | const DATETIME_SHORT = {
  constant DATETIME_SHORT_WITH_SECONDS (line 103) | const DATETIME_SHORT_WITH_SECONDS = {
  constant DATETIME_MED (line 112) | const DATETIME_MED = {
  constant DATETIME_MED_WITH_SECONDS (line 120) | const DATETIME_MED_WITH_SECONDS = {
  constant DATETIME_MED_WITH_WEEKDAY (line 129) | const DATETIME_MED_WITH_WEEKDAY = {
  constant DATETIME_FULL (line 138) | const DATETIME_FULL = {
  constant DATETIME_FULL_WITH_SECONDS (line 147) | const DATETIME_FULL_WITH_SECONDS = {
  constant DATETIME_HUGE (line 157) | const DATETIME_HUGE = {
  constant DATETIME_HUGE_WITH_SECONDS (line 167) | const DATETIME_HUGE_WITH_SECONDS = {

FILE: src/impl/formatter.js
  function stringifyTokens (line 5) | function stringifyTokens(splits, tokenToString) {
  class Formatter (line 44) | class Formatter {
    method create (line 45) | static create(locale, opts = {}) {
    method parseFormat (line 49) | static parseFormat(fmt) {
    method macroTokenToFormatOpts (line 90) | static macroTokenToFormatOpts(token) {
    method constructor (line 94) | constructor(locale, formatOpts) {
    method formatWithSystemDefault (line 100) | formatWithSystemDefault(dt, opts) {
    method dtFormatter (line 108) | dtFormatter(dt, opts = {}) {
    method formatDateTime (line 112) | formatDateTime(dt, opts) {
    method formatDateTimeParts (line 116) | formatDateTimeParts(dt, opts) {
    method formatInterval (line 120) | formatInterval(interval, opts) {
    method resolvedOptions (line 125) | resolvedOptions(dt, opts) {
    method num (line 129) | num(n, p = 0, signDisplay = undefined) {
    method formatDateTimeFromString (line 147) | formatDateTimeFromString(dt, fmt) {
    method formatDurationFromString (line 377) | formatDurationFromString(dur, fmt) {

FILE: src/impl/invalid.js
  class Invalid (line 1) | class Invalid {
    method constructor (line 2) | constructor(reason, explanation) {
    method toMessage (line 7) | toMessage() {

FILE: src/impl/locale.js
  function getCachedLF (line 10) | function getCachedLF(locString, opts = {}) {
  function getCachedDTF (line 21) | function getCachedDTF(locString, opts = {}) {
  function getCachedINF (line 32) | function getCachedINF(locString, opts = {}) {
  function getCachedRTF (line 43) | function getCachedRTF(locString, opts = {}) {
  function systemLocale (line 55) | function systemLocale() {
  function getCachedIntResolvedOptions (line 65) | function getCachedIntResolvedOptions(locString) {
  function getCachedWeekInfo (line 75) | function getCachedWeekInfo(locString) {
  function parseLocaleString (line 90) | function parseLocaleString(localeStr) {
  function intlConfigString (line 127) | function intlConfigString(localeStr, numberingSystem, outputCalendar) {
  function mapMonths (line 146) | function mapMonths(f) {
  function mapWeekdays (line 155) | function mapWeekdays(f) {
  function listStuff (line 164) | function listStuff(loc, length, englishFn, intlFn) {
  function supportsFastNumbers (line 176) | function supportsFastNumbers(loc) {
  class PolyNumberFormatter (line 193) | class PolyNumberFormatter {
    method constructor (line 194) | constructor(intl, forceSimple, opts) {
    method format (line 207) | format(i) {
  class PolyDateFormatter (line 223) | class PolyDateFormatter {
    method constructor (line 224) | constructor(dt, intl, opts) {
    method format (line 269) | format() {
    method formatToParts (line 280) | formatToParts() {
    method resolvedOptions (line 301) | resolvedOptions() {
  class PolyRelFormatter (line 309) | class PolyRelFormatter {
    method constructor (line 310) | constructor(intl, isEnglish, opts) {
    method format (line 317) | format(count, unit) {
    method formatToParts (line 325) | formatToParts(count, unit) {
  class Locale (line 343) | class Locale {
    method fromOpts (line 344) | static fromOpts(opts) {
    method create (line 354) | static create(locale, numberingSystem, outputCalendar, weekSettings, d...
    method resetCache (line 364) | static resetCache() {
    method fromObject (line 373) | static fromObject({ locale, numberingSystem, outputCalendar, weekSetti...
    method constructor (line 377) | constructor(locale, numbering, outputCalendar, weekSettings, specified...
    method fastNumbers (line 395) | get fastNumbers() {
    method listingMode (line 403) | listingMode() {
    method clone (line 411) | clone(alts) {
    method redefaultToEN (line 425) | redefaultToEN(alts = {}) {
    method redefaultToSystem (line 429) | redefaultToSystem(alts = {}) {
    method months (line 433) | months(length, format = false) {
    method weekdays (line 452) | weekdays(length, format = false) {
    method meridiems (line 467) | meridiems() {
    method eras (line 487) | eras(length) {
    method extract (line 503) | extract(dt, intlOpts, field) {
    method numberFormatter (line 510) | numberFormatter(opts = {}) {
    method dtFormatter (line 516) | dtFormatter(dt, intlOpts = {}) {
    method relFormatter (line 520) | relFormatter(opts = {}) {
    method listFormatter (line 524) | listFormatter(opts = {}) {
    method isEnglish (line 528) | isEnglish() {
    method getWeekSettings (line 536) | getWeekSettings() {
    method getStartOfWeek (line 546) | getStartOfWeek() {
    method getMinDaysInFirstWeek (line 550) | getMinDaysInFirstWeek() {
    method getWeekendDays (line 554) | getWeekendDays() {
    method equals (line 558) | equals(other) {
    method toString (line 566) | toString() {

FILE: src/impl/regexParser.js
  function combineRegexes (line 25) | function combineRegexes(...regexes) {
  function combineExtractors (line 30) | function combineExtractors(...extractors) {
  function parse (line 43) | function parse(s, ...patterns) {
  function simpleParse (line 57) | function simpleParse(...keys) {
  function int (line 86) | function int(match, pos, fallback) {
  function extractISOYmd (line 91) | function extractISOYmd(match, cursor) {
  function extractISOTime (line 101) | function extractISOTime(match, cursor) {
  function extractISOOffset (line 112) | function extractISOOffset(match, cursor) {
  function extractIANAZone (line 119) | function extractIANAZone(match, cursor) {
  function extractISODuration (line 133) | function extractISODuration(match) {
  function fromStrings (line 172) | function fromStrings(weekdayStr, yearStr, monthStr, dayStr, hourStr, min...
  function extractRFC2822 (line 196) | function extractRFC2822(match) {
  function preprocessRFC2822 (line 225) | function preprocessRFC2822(s) {
  function extractRFC1123Or850 (line 242) | function extractRFC1123Or850(match) {
  function extractASCII (line 248) | function extractASCII(match) {
  function parseISODate (line 287) | function parseISODate(s) {
  function parseISOIntervalEnd (line 319) | function parseISOIntervalEnd(s) {
  function parseRFC2822Date (line 330) | function parseRFC2822Date(s) {
  function parseHTTPDate (line 334) | function parseHTTPDate(s) {
  function parseISODuration (line 343) | function parseISODuration(s) {
  function parseISOTimeOnly (line 349) | function parseISOTimeOnly(s) {
  function parseSQL (line 362) | function parseSQL(s) {

FILE: src/impl/tokenParser.js
  constant MISSING_FTP (line 9) | const MISSING_FTP = "missing Intl.DateTimeFormat.formatToParts support";
  function intUnit (line 11) | function intUnit(regex, post = (i) => i) {
  constant NBSP (line 15) | const NBSP = String.fromCharCode(160);
  function fixListRegex (line 19) | function fixListRegex(s) {
  function stripInsensitivities (line 25) | function stripInsensitivities(s) {
  function oneOf (line 32) | function oneOf(strings, startIndex) {
  function offset (line 44) | function offset(regex, groups) {
  function simple (line 48) | function simple(regex) {
  function escapeToken (line 52) | function escapeToken(value) {
  function unitForToken (line 60) | function unitForToken(token, loc) {
  function tokenForPart (line 248) | function tokenForPart(part, formatOpts, resolvedOpts) {
  function buildRegex (line 295) | function buildRegex(units) {
  function match (line 300) | function match(input, regex, handlers) {
  function dateTimeFromMatches (line 322) | function dateTimeFromMatches(matches) {
  function getDummyDateTime (line 404) | function getDummyDateTime() {
  function maybeExpandMacroToken (line 412) | function maybeExpandMacroToken(token, locale) {
  function expandMacroTokens (line 427) | function expandMacroTokens(tokens, locale) {
  class TokenParser (line 435) | class TokenParser {
    method constructor (line 436) | constructor(locale, format) {
    method explainFromTokens (line 450) | explainFromTokens(input) {
    method isValid (line 476) | get isValid() {
    method invalidReason (line 480) | get invalidReason() {
  function explainFromTokens (line 485) | function explainFromTokens(locale, input, format) {
  function parseFromTokens (line 490) | function parseFromTokens(locale, input, format) {
  function formatOptsToTokens (line 495) | function formatOptsToTokens(formatOpts, locale) {

FILE: src/impl/util.js
  function isUndefined (line 17) | function isUndefined(o) {
  function isNumber (line 21) | function isNumber(o) {
  function isInteger (line 25) | function isInteger(o) {
  function isString (line 29) | function isString(o) {
  function isDate (line 33) | function isDate(o) {
  function hasRelative (line 39) | function hasRelative() {
  function hasLocaleWeekInfo (line 47) | function hasLocaleWeekInfo() {
  function maybeArray (line 61) | function maybeArray(thing) {
  function bestBy (line 65) | function bestBy(arr, by, compare) {
  function pick (line 81) | function pick(obj, keys) {
  function hasOwnProperty (line 88) | function hasOwnProperty(obj, prop) {
  function validateWeekSettings (line 92) | function validateWeekSettings(settings) {
  function integerBetween (line 116) | function integerBetween(thing, bottom, top) {
  function floorMod (line 121) | function floorMod(x, n) {
  function padStart (line 125) | function padStart(input, n = 2) {
  function parseInteger (line 136) | function parseInteger(string) {
  function parseFloating (line 144) | function parseFloating(string) {
  function parseMillis (line 152) | function parseMillis(fraction) {
  function roundTo (line 162) | function roundTo(number, digits, rounding = "round") {
  function isLeapYear (line 184) | function isLeapYear(year) {
  function daysInYear (line 188) | function daysInYear(year) {
  function daysInMonth (line 192) | function daysInMonth(year, month) {
  function objToLocalTS (line 204) | function objToLocalTS(obj) {
  function firstWeekOffset (line 227) | function firstWeekOffset(year, minDaysInFirstWeek, startOfWeek) {
  function weeksInWeekYear (line 232) | function weeksInWeekYear(weekYear, minDaysInFirstWeek = 4, startOfWeek =...
  function untruncateYear (line 238) | function untruncateYear(year) {
  function parseZoneInfo (line 246) | function parseZoneInfo(ts, offsetFormat, locale, timeZone = null) {
  function signedOffset (line 270) | function signedOffset(offHourStr, offMinuteStr) {
  function asNumber (line 285) | function asNumber(value) {
  function normalizeObject (line 292) | function normalizeObject(obj, normalizer) {
  function formatOffset (line 311) | function formatOffset(offset, format) {
  function timeObject (line 328) | function timeObject(obj) {

FILE: src/impl/zoneUtil.js
  function normalizeZone (line 13) | function normalizeZone(input, defaultZone) {

FILE: src/info.js
  class Info (line 12) | class Info {
    method hasDST (line 18) | static hasDST(zone = Settings.defaultZone) {
    method isValidIANAZone (line 29) | static isValidIANAZone(zone) {
    method normalizeZone (line 47) | static normalizeZone(input) {
    method getStartOfWeek (line 58) | static getStartOfWeek({ locale = null, locObj = null } = {}) {
    method getMinimumDaysInFirstWeek (line 70) | static getMinimumDaysInFirstWeek({ locale = null, locObj = null } = {}) {
    method getWeekendWeekdays (line 81) | static getWeekendWeekdays({ locale = null, locObj = null } = {}) {
    method months (line 103) | static months(
    method monthsFormat (line 123) | static monthsFormat(
    method weekdays (line 144) | static weekdays(length = "long", { locale = null, numberingSystem = nu...
    method weekdaysFormat (line 160) | static weekdaysFormat(
    method meridiems (line 175) | static meridiems({ locale = null } = {}) {
    method eras (line 189) | static eras(length = "short", { locale = null } = {}) {
    method features (line 202) | static features() {

FILE: src/interval.js
  constant INVALID (line 10) | const INVALID = "Invalid Interval";
  function validateStartEnd (line 13) | function validateStartEnd(start, end) {
  class Interval (line 40) | class Interval {
    method constructor (line 44) | constructor(config) {
    method invalid (line 69) | static invalid(reason, explanation = null) {
    method fromDateTimes (line 89) | static fromDateTimes(start, end) {
    method after (line 111) | static after(start, duration) {
    method before (line 123) | static before(end, duration) {
    method fromISO (line 137) | static fromISO(text, opts) {
    method isInterval (line 198) | static isInterval(o) {
    method start (line 206) | get start() {
    method end (line 215) | get end() {
    method lastDateTime (line 223) | get lastDateTime() {
    method isValid (line 231) | get isValid() {
    method invalidReason (line 239) | get invalidReason() {
    method invalidExplanation (line 247) | get invalidExplanation() {
    method length (line 256) | length(unit = "milliseconds") {
    method count (line 269) | count(unit = "milliseconds", opts) {
    method hasSame (line 287) | hasSame(unit) {
    method isEmpty (line 295) | isEmpty() {
    method isAfter (line 304) | isAfter(dateTime) {
    method isBefore (line 314) | isBefore(dateTime) {
    method contains (line 324) | contains(dateTime) {
    method set (line 336) | set({ start, end } = {}) {
    method splitAt (line 346) | splitAt(...dateTimes) {
    method splitBy (line 373) | splitBy(duration) {
    method divideEqually (line 401) | divideEqually(numberOfParts) {
    method overlaps (line 411) | overlaps(other) {
    method abutsStart (line 420) | abutsStart(other) {
    method abutsEnd (line 430) | abutsEnd(other) {
    method engulfs (line 440) | engulfs(other) {
    method equals (line 450) | equals(other) {
    method intersection (line 465) | intersection(other) {
    method union (line 483) | union(other) {
    method merge (line 499) | static merge(intervals) {
    method xor (line 525) | static xor(intervals) {
    method difference (line 558) | difference(...intervals) {
    method toString (line 568) | toString() {
    method toLocaleString (line 603) | toLocaleString(formatOpts = Formats.DATE_SHORT, opts = {}) {
    method toISO (line 615) | toISO(opts) {
    method toISODate (line 626) | toISODate() {
    method toISOTime (line 638) | toISOTime(opts) {
    method toFormat (line 654) | toFormat(dateFormat, { separator = " – " } = {}) {
    method toDuration (line 671) | toDuration(unit, opts) {
    method mapEndpoints (line 685) | mapEndpoints(mapFn) {
  method [Symbol.for("nodejs.util.inspect.custom")] (line 577) | [Symbol.for("nodejs.util.inspect.custom")]() {

FILE: src/luxon.js
  constant VERSION (line 12) | const VERSION = "3.7.2";

FILE: src/settings.js
  class Settings (line 22) | class Settings {
    method now (line 27) | static get now() {
    method now (line 38) | static set now(n) {
    method defaultZone (line 47) | static set defaultZone(zone) {
    method defaultZone (line 56) | static get defaultZone() {
    method defaultLocale (line 64) | static get defaultLocale() {
    method defaultLocale (line 72) | static set defaultLocale(locale) {
    method defaultNumberingSystem (line 80) | static get defaultNumberingSystem() {
    method defaultNumberingSystem (line 88) | static set defaultNumberingSystem(numberingSystem) {
    method defaultOutputCalendar (line 96) | static get defaultOutputCalendar() {
    method defaultOutputCalendar (line 104) | static set defaultOutputCalendar(outputCalendar) {
    method defaultWeekSettings (line 118) | static get defaultWeekSettings() {
    method defaultWeekSettings (line 129) | static set defaultWeekSettings(weekSettings) {
    method twoDigitCutoffYear (line 137) | static get twoDigitCutoffYear() {
    method twoDigitCutoffYear (line 150) | static set twoDigitCutoffYear(cutoffYear) {
    method throwOnInvalid (line 158) | static get throwOnInvalid() {
    method throwOnInvalid (line 166) | static set throwOnInvalid(t) {
    method resetCaches (line 174) | static resetCaches() {

FILE: src/zone.js
  class Zone (line 6) | class Zone {
    method type (line 12) | get type() {
    method name (line 21) | get name() {
    method ianaName (line 31) | get ianaName() {
    method isUniversal (line 40) | get isUniversal() {
    method offsetName (line 53) | offsetName(ts, opts) {
    method formatOffset (line 65) | formatOffset(ts, format) {
    method offset (line 75) | offset(ts) {
    method equals (line 85) | equals(otherZone) {
    method isValid (line 94) | get isValid() {

FILE: src/zones/IANAZone.js
  function makeDTF (line 5) | function makeDTF(zoneName) {
  function hackyOffset (line 34) | function hackyOffset(dtf, date) {
  function partsOffset (line 41) | function partsOffset(dtf, date) {
  class IANAZone (line 62) | class IANAZone extends Zone {
    method create (line 67) | static create(name) {
    method resetCache (line 79) | static resetCache() {
    method isValidSpecifier (line 92) | static isValidSpecifier(s) {
    method isValidZone (line 104) | static isValidZone(zone) {
    method normalizeZone (line 119) | static normalizeZone(zone) {
    method constructor (line 130) | constructor(name) {
    method type (line 147) | get type() {
    method name (line 156) | get name() {
    method isUniversal (line 166) | get isUniversal() {
    method offsetName (line 179) | offsetName(ts, { format, locale }) {
    method formatOffset (line 191) | formatOffset(ts, format) {
    method offset (line 201) | offset(ts) {
    method equals (line 241) | equals(otherZone) {
    method isValid (line 250) | get isValid() {

FILE: src/zones/fixedOffsetZone.js
  class FixedOffsetZone (line 10) | class FixedOffsetZone extends Zone {
    method utcInstance (line 15) | static get utcInstance() {
    method instance (line 27) | static instance(offset) {
    method parseSpecifier (line 39) | static parseSpecifier(s) {
    method constructor (line 49) | constructor(offset) {
    method type (line 60) | get type() {
    method name (line 70) | get name() {
    method ianaName (line 80) | get ianaName() {
    method offsetName (line 94) | offsetName() {
    method formatOffset (line 106) | formatOffset(ts, format) {
    method isUniversal (line 116) | get isUniversal() {
    method offset (line 127) | offset() {
    method equals (line 137) | equals(otherZone) {
    method isValid (line 147) | get isValid() {

FILE: src/zones/invalidZone.js
  class InvalidZone (line 7) | class InvalidZone extends Zone {
    method constructor (line 8) | constructor(zoneName) {
    method type (line 15) | get type() {
    method name (line 20) | get name() {
    method isUniversal (line 25) | get isUniversal() {
    method offsetName (line 30) | offsetName() {
    method formatOffset (line 35) | formatOffset() {
    method offset (line 40) | offset() {
    method equals (line 45) | equals() {
    method isValid (line 50) | get isValid() {

FILE: src/zones/systemZone.js
  class SystemZone (line 10) | class SystemZone extends Zone {
    method instance (line 15) | static get instance() {
    method type (line 23) | get type() {
    method name (line 28) | get name() {
    method isUniversal (line 33) | get isUniversal() {
    method offsetName (line 38) | offsetName(ts, { format, locale }) {
    method formatOffset (line 43) | formatOffset(ts, format) {
    method offset (line 48) | offset(ts) {
    method equals (line 53) | equals(otherZone) {
    method isValid (line 58) | get isValid() {

FILE: tasks/build.js
  constant TRUST_MINIFY (line 11) | const TRUST_MINIFY = false;
  function rollupInputOpts (line 13) | function rollupInputOpts(opts) {
  function rollupOutputOpts (line 64) | function rollupOutputOpts(dest, opts) {
  function babelAndRollup (line 78) | async function babelAndRollup(dest, opts) {
  function buildLibrary (line 85) | async function buildLibrary(dest, opts) {
  function global (line 127) | async function global() {
  function amd (line 137) | async function amd() {
  function node (line 146) | async function node() {
  function cjsBrowser (line 150) | async function cjsBrowser() {
  function es6 (line 154) | async function es6() {
  function globalEs6 (line 163) | async function globalEs6() {
  function buildAll (line 172) | async function buildAll() {

FILE: test/datetime/format.test.js
  class CustomZone (line 24) | class CustomZone extends Zone {
    method constructor (line 25) | constructor(name, offset) {
    method isUniversal (line 31) | get isUniversal() {
    method isValid (line 35) | get isValid() {
    method name (line 39) | get name() {
    method type (line 43) | get type() {
    method equals (line 47) | equals(zone) {
    method offset (line 51) | offset(_ms) {
    method offsetName (line 55) | offsetName(_ms, { format }) {
    method formatOffset (line 63) | formatOffset(...args) {

FILE: test/datetime/math.test.js
  function createDateTime (line 6) | function createDateTime() {

FILE: test/datetime/tokenParse.test.js
  function parseMeridiem (line 79) | function parseMeridiem(input, isAM) {
  function keyCount (line 857) | function keyCount(o) {

FILE: test/interval/many.test.js
  function xor (line 116) | function xor(items, expected) {
  function diff (line 172) | function diff(interval, items, expected) {
Condensed preview — 149 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (894K chars).
[
  {
    "path": ".agignore",
    "chars": 25,
    "preview": "/build\npackage-lock.json\n"
  },
  {
    "path": ".babelrc",
    "chars": 47,
    "preview": "{\n  \"presets\": [\n    \"@babel/preset-env\"\n  ]\n}\n"
  },
  {
    "path": ".editorconfig",
    "chars": 189,
    "preview": "root = true\n\n[*]\ncharset = utf-8\nindent_size = 2\nend_of_line = lf\nindent_style = space\ninsert_final_newline = false\ntrim"
  },
  {
    "path": ".gitattributes",
    "chars": 108,
    "preview": "scripts/* linguist-vendored\ndocker/* linguist-vendored\nsite/** linguist-vendored\n.husky/* linguist-vendored\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/bug_report.md",
    "chars": 599,
    "preview": "---\nname: Bug report\nabout: Create a report to help us improve\ntitle: \"\"\nlabels: bug\n---\n\n**Describe the bug**\nA clear a"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/feature_request.md",
    "chars": 589,
    "preview": "---\nname: Feature request\nabout: Suggest an idea for this project\ntitle: \"\"\nlabels: enhancement\n---\n\n**Is your feature r"
  },
  {
    "path": ".github/workflows/test.yml",
    "chars": 814,
    "preview": "name: Test\n\non:\n  push:\n    branches: [master]\n  pull_request:\n    branches: [master]\n\njobs:\n  build-and-test:\n    runs-"
  },
  {
    "path": ".gitignore",
    "chars": 117,
    "preview": "node_modules\n.tern-port\n/build\n#*\n.#*\ncoverage/\n.DS_Store\n.external-ecmascript.js\n.idea\n.vscode\ntest/scratch.test.js\n"
  },
  {
    "path": ".husky/.gitignore",
    "chars": 2,
    "preview": "_\n"
  },
  {
    "path": ".husky/pre-commit",
    "chars": 58,
    "preview": "#!/bin/sh\n. \"$(dirname \"$0\")/_/husky.sh\"\n\nnpx lint-staged\n"
  },
  {
    "path": ".prettierrc",
    "chars": 22,
    "preview": "{ \"printWidth\": 100 }\n"
  },
  {
    "path": "CHANGELOG.md",
    "chars": 9617,
    "preview": "# Changelog\n\n# 3.7.2 (2025-07-09)\n- Fix ES6 packaging\n\n# 3.7.1 (2025-07-09)\n- Revert change in ES6 packaging\n\n# 3.7.0 (2"
  },
  {
    "path": "CONTRIBUTING.md",
    "chars": 5134,
    "preview": "# Contributing to Luxon\n\n## General guidelines\n\nPatches are welcome. Luxon is at this point just a baby and it could use"
  },
  {
    "path": "LICENSE.md",
    "chars": 1076,
    "preview": "Copyright 2019 JS Foundation and other contributors\n\nPermission is hereby granted, free of charge, to any person obtaini"
  },
  {
    "path": "README.md",
    "chars": 2225,
    "preview": "# Luxon\n\n[![MIT License][license-image]][license] [![Build Status][github-action-image]][github-action-url] [![NPM versi"
  },
  {
    "path": "babel.config.js",
    "chars": 53,
    "preview": "module.exports = { presets: [\"@babel/preset-env\"] };\n"
  },
  {
    "path": "benchmarks/datetime.js",
    "chars": 3151,
    "preview": "import Benchmark from \"benchmark\";\nimport DateTime from \"../src/datetime.js\";\nimport Settings from \"../src/settings.js\";"
  },
  {
    "path": "benchmarks/index.js",
    "chars": 251,
    "preview": "import dateTimeSuites from \"./datetime.js\";\nimport infoSuites from \"./info.js\";\n\nconst allSuites = [...dateTimeSuites, ."
  },
  {
    "path": "benchmarks/info.js",
    "chars": 2921,
    "preview": "import Benchmark from \"benchmark\";\nimport Info from \"../src/info.js\";\nimport Locale from \"../src/impl/locale.js\";\n\nfunct"
  },
  {
    "path": "benchmarks/package.json",
    "chars": 23,
    "preview": "{\n  \"type\": \"module\"\n}\n"
  },
  {
    "path": "codecov.yml",
    "chars": 127,
    "preview": "comment: false\ncoverage:\n  status:\n    project:\n      default:\n        target: auto\n        threshold: null\n        base"
  },
  {
    "path": "docker/Dockerfile",
    "chars": 127,
    "preview": "FROM library/node:15-slim\n\nENV HUSKY_SKIP_INSTALL=1\n\nENV LANG=en_US.utf8\nENV LIMIT_JEST=yes\nENV CI=yes\nENV TZ=America/Ne"
  },
  {
    "path": "docker/build",
    "chars": 58,
    "preview": "#!/usr/bin/env bash\ndocker build docker -t icambron/luxon\n"
  },
  {
    "path": "docker/npm",
    "chars": 89,
    "preview": "#!/usr/bin/env bash\ndocker run -it --rm -v $(pwd):/luxon -w /luxon icambron/luxon npm $@\n"
  },
  {
    "path": "docker/push",
    "chars": 47,
    "preview": "#!/usr/bin/env bash\ndocker push icambron/luxon\n"
  },
  {
    "path": "docker/readme.md",
    "chars": 270,
    "preview": "Luxon provides a Docker container and some wrapping scripts to make it easier to run the tests.\n\n  1. The Dockerfile is "
  },
  {
    "path": "docs/calendars.md",
    "chars": 3328,
    "preview": "# Calendars\n\nThis covers Luxon's support for various calendar systems. If you don't need to use non-standard calendars, "
  },
  {
    "path": "docs/formatting.md",
    "chars": 23383,
    "preview": "# Formatting\n\nThis section covers creating strings to represent a DateTime. There are three types of formatting capabili"
  },
  {
    "path": "docs/home.md",
    "chars": 1024,
    "preview": "## Luxon\n\nLuxon is a library for dealing with dates and times in JavaScript.\n\n```js\nDateTime.now().setZone('America/New_"
  },
  {
    "path": "docs/install.md",
    "chars": 3211,
    "preview": "# Install guide\n\nLuxon provides different builds for different JS environments. See below for a link to the right one an"
  },
  {
    "path": "docs/intl.md",
    "chars": 9728,
    "preview": "# Intl\n\nLuxon uses the native Intl API to provide easy-to-use internationalization. A quick example:\n\n```js\nDateTime.now"
  },
  {
    "path": "docs/math.md",
    "chars": 14658,
    "preview": "# Math\n\nThis page covers some oddball topics related to date and time math, which has some quirky corner cases.\n\n## Cale"
  },
  {
    "path": "docs/matrix.md",
    "chars": 4071,
    "preview": "# Support matrix\n\nThis page covers what platforms are supported by Luxon and what caveats apply to them.\n\n## Official su"
  },
  {
    "path": "docs/moment.md",
    "chars": 17327,
    "preview": "# For Moment users\n\nLuxon borrows lots of ideas from [Moment.js](https://momentjs.com), but there are a lot of differenc"
  },
  {
    "path": "docs/parsing.md",
    "chars": 15069,
    "preview": "# Parsing\n\nLuxon is not an NLP tool and isn't suitable for all date parsing jobs. But it can do some parsing:\n\n1.  Direc"
  },
  {
    "path": "docs/tour.md",
    "chars": 8363,
    "preview": "# A quick tour\n\nLuxon is a library that makes it easier to work with dates and times in JavaScript. If you want, add and"
  },
  {
    "path": "docs/upgrading.md",
    "chars": 3796,
    "preview": "# Upgrading Luxon\n\n## 2.x to 3.0\n\nVersion 3.0 has one breaking change: specifying \"system\" as the zone always results in"
  },
  {
    "path": "docs/validity.md",
    "chars": 2995,
    "preview": "# Validity\n\n## Invalid DateTimes\n\nOne of the most irritating aspects of programming with time is that it's possible to e"
  },
  {
    "path": "docs/why.md",
    "chars": 4630,
    "preview": "# Why does Luxon exist?\n\nWhat's the deal with this whole Luxon thing anyway? Why did I write it? How is it related to th"
  },
  {
    "path": "docs/zones.md",
    "chars": 17600,
    "preview": "# Time zones and offsets\n\nLuxon has support for time zones. This page explains how to use them.\n\n## Don't worry!\n\nYou _u"
  },
  {
    "path": "jest.config.js",
    "chars": 214,
    "preview": "module.exports = {\n  testEnvironment: \"node\",\n  roots: [\"test\"],\n  coverageDirectory: \"build/coverage\",\n  collectCoverag"
  },
  {
    "path": "package.json",
    "chars": 2872,
    "preview": "{\n  \"name\": \"luxon\",\n  \"version\": \"3.7.2\",\n  \"description\": \"Immutable date wrapper\",\n  \"author\": \"Isaac Cambron\",\n  \"ke"
  },
  {
    "path": "scripts/bootstrap.js",
    "chars": 242,
    "preview": "const luxon = require(\"../build/node/luxon\");\nglobal.DateTime = luxon.DateTime;\nglobal.Duration = luxon.Duration;\nglobal"
  },
  {
    "path": "scripts/deploy-site",
    "chars": 6440,
    "preview": "#!/usr/bin/env bash\nset -o errexit #abort if any command fails\nme=$(basename \"$0\")\n\nhelp_message=\"\\\nUsage: $me [-c FILE]"
  },
  {
    "path": "scripts/jest",
    "chars": 90,
    "preview": "TZ=\"America/New_York\" NODE_ICU_DATA=\"$(pwd)/node_modules/full-icu\" LANG=en_US.utf8 jest $@"
  },
  {
    "path": "scripts/readme.md",
    "chars": 234,
    "preview": "These are scripts useful for development:\n\n 1. `test` is a script for more conveniently running the tests if you've inst"
  },
  {
    "path": "scripts/release",
    "chars": 124,
    "preview": "#!/usr/bin/env bash\n./scripts/version || exit $?\n\nnpm run build\nnpm run site\nnpm publish\n./scripts/tag\n./scripts/deploy-"
  },
  {
    "path": "scripts/repl",
    "chars": 64,
    "preview": "#!/bin/bash\nLANG=en-US.utf8 node -i -r \"./scripts/bootstrap.js\"\n"
  },
  {
    "path": "scripts/tag",
    "chars": 179,
    "preview": "#!/usr/bin/env bash\n./scripts/version || exit $?\n\nPACKAGE_VERSION=$(node -p \"require('./package.json').version\")\n\ngit ta"
  },
  {
    "path": "scripts/test",
    "chars": 70,
    "preview": "#!/usr/bin/env bash\nTZ=\"America/New_York\" LANG=en_US.utf8 npm run test"
  },
  {
    "path": "scripts/version",
    "chars": 839,
    "preview": "#!/usr/bin/env bash\n\nabort() {\n  echo \"ERROR: $1\"\n  exit 1\n}\n\nif [[ -x $(which ggrep) ]]\nthen\n  grepper='ggrep'\nelse\n  g"
  },
  {
    "path": "site/.nojekyll",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "site/demo/demo.css",
    "chars": 145,
    "preview": ".divider {\n  color: blue;\n}\n\n.code {\n  display: inline-block;\n  font-family: monospace;\n}\n\n.result {\n  color: darkgreen;"
  },
  {
    "path": "site/demo/demo.js",
    "chars": 4101,
    "preview": "function demo(luxon) {\n  const DateTime = luxon.DateTime;\n  const Duration = luxon.Duration;\n  const Info = luxon.Info;\n"
  },
  {
    "path": "site/demo/global.html",
    "chars": 298,
    "preview": "<!DOCTYPE html>\n<html>\n    <head>\n        <link rel='stylesheet' href='demo.css'/>\n        <script src='../global/luxon."
  },
  {
    "path": "site/demo/requirejs.html",
    "chars": 491,
    "preview": "<!DOCTYPE html>\n<html>\n    <head>\n        <link rel='stylesheet' href='demo.css'/>\n        <script src='https://cdnjs.cl"
  },
  {
    "path": "site/docs/_coverpage.md",
    "chars": 369,
    "preview": "![logo](_media/Luxon_icon_64x64.png)\n\n# Luxon <small>3.x</small>\n\n> A powerful, modern, and friendly wrapper for JavaScr"
  },
  {
    "path": "site/docs/_sidebar.md",
    "chars": 422,
    "preview": "* [Home](/)\n* [Install guide](install.md)\n* [A quick tour](tour.md)\n* [Upgrade guide](upgrading.md)\n* [Intl](intl.md)\n* "
  },
  {
    "path": "site/index.html",
    "chars": 1602,
    "preview": "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n  <meta charset=\"UTF-8\">\n  <title>luxon - Immutable date wrapper</title>\n  <meta"
  },
  {
    "path": "site/plugins/dark-theme-toggle.css",
    "chars": 1440,
    "preview": "#docsify-dark-theme-toggle {\n  position: absolute;\n  display: inline-block;\n  width: 52px;\n  height: 28px;\n  margin-left"
  },
  {
    "path": "site/plugins/dark-theme-toggle.js",
    "chars": 923,
    "preview": "(() => {\n  const darkThemeTogglePlugin = (hook, vm) => {\n    const TOGGLE_ID = \"docsify-dark-theme-toggle\",\n      dom = "
  },
  {
    "path": "src/datetime.js",
    "chars": 98635,
    "preview": "import Duration from \"./duration.js\";\nimport Interval from \"./interval.js\";\nimport Settings from \"./settings.js\";\nimport"
  },
  {
    "path": "src/duration.js",
    "chars": 35274,
    "preview": "import { InvalidArgumentError, InvalidDurationError, InvalidUnitError } from \"./errors.js\";\nimport Formatter from \"./imp"
  },
  {
    "path": "src/errors.js",
    "chars": 1047,
    "preview": "// these aren't really private, but nor are they really useful to document\n\n/**\n * @private\n */\nclass LuxonError extends"
  },
  {
    "path": "src/impl/conversions.js",
    "chars": 6468,
    "preview": "import {\n  integerBetween,\n  isLeapYear,\n  timeObject,\n  daysInYear,\n  daysInMonth,\n  weeksInWeekYear,\n  isInteger,\n  is"
  },
  {
    "path": "src/impl/diff.js",
    "chars": 3015,
    "preview": "import Duration from \"../duration.js\";\n\nfunction dayDiff(earlier, later) {\n  const utcDayStart = (dt) => dt.toUTC(0, { k"
  },
  {
    "path": "src/impl/digits.js",
    "chars": 2351,
    "preview": "const numberingSystems = {\n  arab: \"[\\u0660-\\u0669]\",\n  arabext: \"[\\u06F0-\\u06F9]\",\n  bali: \"[\\u1B50-\\u1B59]\",\n  beng: \""
  },
  {
    "path": "src/impl/english.js",
    "chars": 5820,
    "preview": "import * as Formats from \"./formats.js\";\nimport { pick } from \"./util.js\";\n\nfunction stringify(obj) {\n  return JSON.stri"
  },
  {
    "path": "src/impl/formats.js",
    "chars": 2249,
    "preview": "/**\n * @private\n */\n\nconst n = \"numeric\",\n  s = \"short\",\n  l = \"long\";\n\nexport const DATE_SHORT = {\n  year: n,\n  month: "
  },
  {
    "path": "src/impl/formatter.js",
    "chars": 13832,
    "preview": "import * as English from \"./english.js\";\nimport * as Formats from \"./formats.js\";\nimport { padStart } from \"./util.js\";\n"
  },
  {
    "path": "src/impl/invalid.js",
    "chars": 282,
    "preview": "export default class Invalid {\n  constructor(reason, explanation) {\n    this.reason = reason;\n    this.explanation = exp"
  },
  {
    "path": "src/impl/locale.js",
    "chars": 16851,
    "preview": "import { hasLocaleWeekInfo, hasRelative, padStart, roundTo, validateWeekSettings } from \"./util.js\";\nimport * as English"
  },
  {
    "path": "src/impl/regexParser.js",
    "chars": 11536,
    "preview": "import {\n  untruncateYear,\n  signedOffset,\n  parseInteger,\n  parseMillis,\n  isUndefined,\n  parseFloating,\n} from \"./util"
  },
  {
    "path": "src/impl/tokenParser.js",
    "chars": 13001,
    "preview": "import { parseMillis, isUndefined, untruncateYear, signedOffset, hasOwnProperty } from \"./util.js\";\nimport Formatter fro"
  },
  {
    "path": "src/impl/util.js",
    "chars": 8972,
    "preview": "/*\n  This is just a junk drawer, containing anything used across multiple classes.\n  Because Luxon is small(ish), this s"
  },
  {
    "path": "src/impl/zoneUtil.js",
    "chars": 1253,
    "preview": "/**\n * @private\n */\n\nimport Zone from \"../zone.js\";\nimport IANAZone from \"../zones/IANAZone.js\";\nimport FixedOffsetZone "
  },
  {
    "path": "src/info.js",
    "chars": 9239,
    "preview": "import DateTime from \"./datetime.js\";\nimport Settings from \"./settings.js\";\nimport Locale from \"./impl/locale.js\";\nimpor"
  },
  {
    "path": "src/interval.js",
    "chars": 23805,
    "preview": "import DateTime, { friendlyDateTime, parseDataToDateTime } from \"./datetime.js\";\nimport Duration from \"./duration.js\";\ni"
  },
  {
    "path": "src/luxon.js",
    "chars": 586,
    "preview": "import DateTime from \"./datetime.js\";\nimport Duration from \"./duration.js\";\nimport Interval from \"./interval.js\";\nimport"
  },
  {
    "path": "src/package.json",
    "chars": 45,
    "preview": "{\n  \"type\": \"module\",\n  \"version\": \"3.7.2\"\n}\n"
  },
  {
    "path": "src/settings.js",
    "chars": 5577,
    "preview": "import SystemZone from \"./zones/systemZone.js\";\nimport IANAZone from \"./zones/IANAZone.js\";\nimport Locale from \"./impl/l"
  },
  {
    "path": "src/zone.js",
    "chars": 2270,
    "preview": "import { ZoneIsAbstractError } from \"./errors.js\";\n\n/**\n * @interface\n */\nexport default class Zone {\n  /**\n   * The typ"
  },
  {
    "path": "src/zones/IANAZone.js",
    "chars": 7117,
    "preview": "import { formatOffset, parseZoneInfo, isUndefined, objToLocalTS } from \"../impl/util.js\";\nimport Zone from \"../zone.js\";"
  },
  {
    "path": "src/zones/fixedOffsetZone.js",
    "chars": 3608,
    "preview": "import { formatOffset, signedOffset } from \"../impl/util.js\";\nimport Zone from \"../zone.js\";\n\nlet singleton = null;\n\n/**"
  },
  {
    "path": "src/zones/invalidZone.js",
    "chars": 763,
    "preview": "import Zone from \"../zone.js\";\n\n/**\n * A zone that failed to parse. You should never need to instantiate this.\n * @imple"
  },
  {
    "path": "src/zones/systemZone.js",
    "chars": 1147,
    "preview": "import { formatOffset, parseZoneInfo } from \"../impl/util.js\";\nimport Zone from \"../zone.js\";\n\nlet singleton = null;\n\n/*"
  },
  {
    "path": "tasks/build.js",
    "chars": 4031,
    "preview": "const rollup = require(\"rollup\"),\n  { babel } = require(\"@rollup/plugin-babel\"),\n  { terser } = require(\"rollup-plugin-t"
  },
  {
    "path": "tasks/buildAll.js",
    "chars": 74,
    "preview": "const { buildAll } = require(\"./build\");\nbuildAll().catch(console.error);\n"
  },
  {
    "path": "tasks/buildGlobal.js",
    "chars": 80,
    "preview": "const { buildGlobal } = require(\"./build\");\nbuildGlobal().catch(console.error);\n"
  },
  {
    "path": "tasks/buildNode.js",
    "chars": 76,
    "preview": "const { buildNode } = require(\"./build\");\nbuildNode().catch(console.error);\n"
  },
  {
    "path": "test/datetime/create.test.js",
    "chars": 31943,
    "preview": "/* global test expect */\n\nimport { DateTime, Settings } from \"../../src/luxon\";\nimport Helpers, { supportsMinDaysInFirst"
  },
  {
    "path": "test/datetime/degrade.test.js",
    "chars": 332,
    "preview": "/* global expect */\nimport { DateTime } from \"../../src/luxon\";\n\nconst Helpers = require(\"../helpers\");\n\nHelpers.without"
  },
  {
    "path": "test/datetime/diff.test.js",
    "chars": 11125,
    "preview": "/* global test expect */\n\nimport { DateTime } from \"../../src/luxon\";\n\nconst Helpers = require(\"../helpers\");\n\n//------\n"
  },
  {
    "path": "test/datetime/dst.test.js",
    "chars": 6155,
    "preview": "/* global test expect */\n\nimport { DateTime, Settings } from \"../../src/luxon\";\n\nconst dateTimeConstructors = {\n  fromOb"
  },
  {
    "path": "test/datetime/equality.test.js",
    "chars": 1371,
    "preview": "/* global test expect */\n\nimport { DateTime } from \"../../src/luxon\";\n\ntest(\"equals self\", () => {\n  const l = DateTime."
  },
  {
    "path": "test/datetime/format.test.js",
    "chars": 23900,
    "preview": "/* global test expect */\n\nimport { DateTime, Zone, FixedOffsetZone } from \"../../src/luxon\";\nimport { InvalidUnitError }"
  },
  {
    "path": "test/datetime/getters.test.js",
    "chars": 5781,
    "preview": "/* global test expect */\n\nimport { DateTime } from \"../../src/luxon\";\nimport Settings from \"../../src/settings\";\n\nconst "
  },
  {
    "path": "test/datetime/info.test.js",
    "chars": 865,
    "preview": "/* global test expect */\n\nimport { DateTime } from \"../../src/luxon\";\n\nconst dateTime = DateTime.fromJSDate(new Date(198"
  },
  {
    "path": "test/datetime/invalid.test.js",
    "chars": 3604,
    "preview": "/* global test expect */\n\nimport { DateTime, Settings } from \"../../src/luxon\";\n\nconst organic1 = DateTime.utc(2014, 13,"
  },
  {
    "path": "test/datetime/localeWeek.test.js",
    "chars": 11714,
    "preview": "/* global test expect */\n\nimport { DateTime, Info } from \"../../src/luxon\";\nimport Helpers, { supportsMinDaysInFirstWeek"
  },
  {
    "path": "test/datetime/many.test.js",
    "chars": 2750,
    "preview": "/* global test expect */\n\nimport { DateTime } from \"../../src/luxon\";\n\n//------\n// min\n//-------\ntest(\"DateTime.min retu"
  },
  {
    "path": "test/datetime/math.test.js",
    "chars": 16259,
    "preview": "/* global test expect */\n\nimport { DateTime, Duration } from \"../../src/luxon\";\nimport { casualMatrix } from \"../../src/"
  },
  {
    "path": "test/datetime/misc.test.js",
    "chars": 4396,
    "preview": "/* global test expect */\nimport { DateTime } from \"../../src/luxon\";\n\n// you hate to see a class like this, but here we "
  },
  {
    "path": "test/datetime/proto.test.js",
    "chars": 332,
    "preview": "/* global test expect */\nimport { DateTime } from \"../../src/luxon\";\n\ntest(\"DateTime prototype properties should not thr"
  },
  {
    "path": "test/datetime/reconfigure.test.js",
    "chars": 1221,
    "preview": "/* global test expect */\n\nimport { DateTime } from \"../../src/luxon\";\n\nconst dt = DateTime.fromObject(\n  {},\n  {\n    loc"
  },
  {
    "path": "test/datetime/regexParse.test.js",
    "chars": 23196,
    "preview": "/* global test expect */\n\nimport { DateTime } from \"../../src/luxon\";\nimport { withNow } from \"../helpers\";\n\n//------\n//"
  },
  {
    "path": "test/datetime/relative.test.js",
    "chars": 15380,
    "preview": "import DateTime from \"../../src/datetime\";\n\nconst Helpers = require(\"../helpers\");\n\n/* global expect test */\n\n//------\n/"
  },
  {
    "path": "test/datetime/set.test.js",
    "chars": 11106,
    "preview": "/* global test expect */\n\nimport { DateTime } from \"../../src/luxon\";\nimport Helpers, { supportsMinDaysInFirstWeek } fro"
  },
  {
    "path": "test/datetime/toFormat.test.js",
    "chars": 24445,
    "preview": "/* global test expect */\n\nimport { DateTime } from \"../../src/luxon\";\n\nconst dt = DateTime.fromObject(\n  {\n    year: 198"
  },
  {
    "path": "test/datetime/tokenParse.test.js",
    "chars": 41550,
    "preview": "/* global test expect */\nimport { DateTime } from \"../../src/luxon\";\nimport Helpers, { cldrMajorVersion } from \"../helpe"
  },
  {
    "path": "test/datetime/transform.test.js",
    "chars": 1702,
    "preview": "/* global test expect */\n\nimport { DateTime } from \"../../src/luxon\";\n\nconst dtMaker = () =>\n    DateTime.fromObject(\n  "
  },
  {
    "path": "test/datetime/typecheck.test.js",
    "chars": 774,
    "preview": "/* global test expect */\nimport { DateTime } from \"../../src/luxon\";\n\n//------\n// #isDateTime()\n//------\ntest(\"DateTime#"
  },
  {
    "path": "test/datetime/zone.test.js",
    "chars": 11842,
    "preview": "/* global test expect */\n\nimport { DateTime, Settings, IANAZone } from \"../../src/luxon\";\n\nvar Helpers = require(\"../hel"
  },
  {
    "path": "test/duration/accuracy.test.js",
    "chars": 987,
    "preview": "/* global test expect */\n\nimport { Duration } from \"../../src/luxon\";\n\nconst convert = (amt, from, to, accuracy) =>\n  Du"
  },
  {
    "path": "test/duration/create.test.js",
    "chars": 4273,
    "preview": "/* global test expect */\n\nimport { Duration } from \"../../src/luxon\";\n\n//------\n// .fromObject()\n//-------\ntest(\"Duratio"
  },
  {
    "path": "test/duration/customMatrix.test.js",
    "chars": 1197,
    "preview": "/* global test expect */\n\nimport { Duration } from \"../../src/luxon\";\nimport { casualMatrix } from \"../../src/duration\";"
  },
  {
    "path": "test/duration/equality.test.js",
    "chars": 2837,
    "preview": "/* global test expect */\nimport { Duration } from \"../../src/luxon\";\n\ntest(\"equals self\", () => {\n  const l = Duration.f"
  },
  {
    "path": "test/duration/format.test.js",
    "chars": 15723,
    "preview": "/* global test expect */\nimport { Duration } from \"../../src/luxon\";\n\nconst dur = () =>\n  Duration.fromObject({\n    year"
  },
  {
    "path": "test/duration/getters.test.js",
    "chars": 1886,
    "preview": "/* global test expect */\n\nimport { Duration } from \"../../src/luxon\";\n\nconst dur = Duration.fromObject({\n    years: 1,\n "
  },
  {
    "path": "test/duration/info.test.js",
    "chars": 469,
    "preview": "/* global test expect */\n\nimport { Duration } from \"../../src/luxon\";\n\nconst dur = Duration.fromObject({\n  years: 1,\n  m"
  },
  {
    "path": "test/duration/invalid.test.js",
    "chars": 1767,
    "preview": "/* global test expect */\n\nimport { Duration, DateTime, Settings } from \"../../src/luxon\";\n\ntest(\"Explicitly invalid dura"
  },
  {
    "path": "test/duration/math.test.js",
    "chars": 6314,
    "preview": "/* global test expect */\n\nimport { Duration } from \"../../src/luxon\";\n\n//------\n// #plus()\n//------\ntest(\"Duration#plus "
  },
  {
    "path": "test/duration/parse.test.js",
    "chars": 4099,
    "preview": "/* global test expect */\n\nimport { Duration } from \"../../src/luxon\";\n\n//------\n// #fromISO()\n//------\n\nconst check = (s"
  },
  {
    "path": "test/duration/proto.test.js",
    "chars": 327,
    "preview": "import { Duration } from \"../../src/luxon\";\n\ntest(\"Duration prototype properties should not throw when addressed\", () =>"
  },
  {
    "path": "test/duration/reconfigure.test.js",
    "chars": 1312,
    "preview": "/* global test expect */\n\nimport { Duration } from \"../../src/luxon\";\n\nconst dur = Duration.fromObject(\n  {\n    years: 1"
  },
  {
    "path": "test/duration/set.test.js",
    "chars": 1137,
    "preview": "/* global test expect */\nimport { Duration } from \"../../src/luxon\";\n\n//------\n// years/months/days/hours/minutes/second"
  },
  {
    "path": "test/duration/typecheck.test.js",
    "chars": 859,
    "preview": "/* global test expect */\n\nimport { Duration } from \"../../src/luxon\";\n\n//------\n// #isDuration\n//-------\ntest(\"Duration#"
  },
  {
    "path": "test/duration/units.test.js",
    "chars": 11989,
    "preview": "/* global test expect */\nimport { Duration } from \"../../src/luxon\";\n\n//------\n// #shiftTo()\n//-------\ntest(\"Duration#sh"
  },
  {
    "path": "test/helpers.js",
    "chars": 2168,
    "preview": "/* global test */\nimport { DateTime, Settings } from \"../src/luxon\";\nimport { hasLocaleWeekInfo } from \"../src/impl/util"
  },
  {
    "path": "test/impl/english.test.js",
    "chars": 5883,
    "preview": "/* global test expect */\nimport * as Formats from \"../../src/impl/formats\";\nimport { formatRelativeTime, formatString, w"
  },
  {
    "path": "test/info/features.test.js",
    "chars": 526,
    "preview": "/* global test expect */\nimport { Info } from \"../../src/luxon\";\n\nconst Helpers = require(\"../helpers\");\n\ntest(\"Info.fea"
  },
  {
    "path": "test/info/listers.test.js",
    "chars": 7541,
    "preview": "/* global test expect */\n\nimport { Info } from \"../../src/luxon\";\n\nimport Helpers from \"../helpers\";\nconst withDefaultLo"
  },
  {
    "path": "test/info/localeWeek.test.js",
    "chars": 2167,
    "preview": "/* global test expect */\nimport { Info } from \"../../src/luxon\";\nimport { supportsMinDaysInFirstWeek } from \"../helpers\""
  },
  {
    "path": "test/info/zones.test.js",
    "chars": 3656,
    "preview": "/* global test expect */\n\nimport {\n  Info,\n  FixedOffsetZone,\n  IANAZone,\n  InvalidZone,\n  SystemZone,\n  Settings,\n} fro"
  },
  {
    "path": "test/interval/create.test.js",
    "chars": 3923,
    "preview": "/* global test expect */\nimport { DateTime, Interval, Duration, Settings } from \"../../src/luxon\";\nimport Helpers from \""
  },
  {
    "path": "test/interval/format.test.js",
    "chars": 7949,
    "preview": "/* global test expect */\nimport { Interval, DateTime } from \"../../src/luxon\";\n\nconst fromISOs = (s, e) =>\n    DateTime."
  },
  {
    "path": "test/interval/getters.test.js",
    "chars": 643,
    "preview": "/* global test expect */\nimport { Interval } from \"../../src/luxon\";\n\nconst Helpers = require(\"../helpers\");\n\nconst toda"
  },
  {
    "path": "test/interval/info.test.js",
    "chars": 9519,
    "preview": "/* global test expect */\nimport { DateTime, Interval } from \"../../src/luxon\";\n\nconst Helpers = require(\"../helpers\");\n\n"
  },
  {
    "path": "test/interval/localeWeek.test.js",
    "chars": 904,
    "preview": "/* global test expect */\n\nimport { DateTime, Interval } from \"../../src/luxon\";\n\n//------\n// .count() with useLocaleWeek"
  },
  {
    "path": "test/interval/many.test.js",
    "chars": 15014,
    "preview": "/* global test expect */\nimport { DateTime, Interval, Duration } from \"../../src/luxon\";\n\nconst Helpers = require(\"../he"
  },
  {
    "path": "test/interval/parse.test.js",
    "chars": 11692,
    "preview": "/* global test expect */\nimport { Interval } from \"../../src/luxon\";\nimport Helpers from \"../helpers\";\n\nconst withThrowO"
  },
  {
    "path": "test/interval/proto.test.js",
    "chars": 387,
    "preview": "/* global test expect */\nimport { DateTime } from \"../../src/luxon\";\n\ntest(\"Interval prototype properties should not thr"
  },
  {
    "path": "test/interval/setter.test.js",
    "chars": 637,
    "preview": "/* global test expect */\nimport { Interval } from \"../../src/luxon\";\n\nconst Helpers = require(\"../helpers\");\n\nconst toda"
  },
  {
    "path": "test/interval/typecheck.test.js",
    "chars": 770,
    "preview": "/* global test expect */\n\nimport { Interval, DateTime } from \"../../src/luxon\";\n\n//------\n// #isInterval\n//-------\ntest("
  },
  {
    "path": "test/zones/IANA.test.js",
    "chars": 5679,
    "preview": "/* global test expect */\nimport { FixedOffsetZone, IANAZone } from \"../../src/luxon\";\n\ntest(\"IANAZone.create returns a s"
  },
  {
    "path": "test/zones/fixedOffset.test.js",
    "chars": 3323,
    "preview": "/* global test expect */\nimport { FixedOffsetZone, IANAZone } from \"../../src/luxon\";\n\ntest(\"FixedOffsetZone.utcInstance"
  },
  {
    "path": "test/zones/invalid.test.js",
    "chars": 586,
    "preview": "/* global test expect */\nimport { InvalidZone } from \"../../src/luxon\";\n\ntest(\"InvalidZone\", () => {\n  const zone = new "
  },
  {
    "path": "test/zones/local.test.js",
    "chars": 871,
    "preview": "/* global test expect */\nimport { SystemZone } from \"../../src/luxon\";\n\ntest(\"SystemZone.instance returns a singleton\", "
  },
  {
    "path": "test/zones/zoneInterface.test.js",
    "chars": 166,
    "preview": "/* global test expect */\nimport { Zone } from \"../../src/luxon\";\n\ntest(\"You can instantiate Zone directly\", () => {\n  ex"
  }
]

About this extraction

This page contains the full source code of the moment/luxon GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 149 files (828.1 KB), approximately 243.1k tokens, and a symbol index with 591 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!