# Day.js User Guide

Day.js is a minimalist JavaScript library for parsing, validating, manipulating, and displaying dates and times. It ships a largely **Moment.js-compatible API** in a **~2&nbsp;KB** immutable, chainable package, with optional plugins and 140+ locales loaded only when you need them.

If you already know Moment.js, you already know how to use Day.js.

```js
dayjs().startOf('month').add(1, 'day').set('year', 2018).format('YYYY-MM-DD HH:mm:ss')
```

This guide covers everything you can do with Day.js from application code: installing it, creating date objects, reading and changing their parts, formatting and comparing them, enabling each of the 37 official plugins, and switching locales. Architecture, the plugin authoring model, build internals, and security considerations live in the companion **Admin Guide**.

---

## Table of Contents

1. [Quick Start](#1-quick-start)
2. [Why Day.js](#2-why-dayjs)
3. [Installation](#3-installation)
4. [Core Concepts](#4-core-concepts)
5. [Parsing — Creating Day.js Objects](#5-parsing--creating-dayjs-objects)
6. [Get and Set](#6-get-and-set)
7. [Manipulating Dates](#7-manipulating-dates)
8. [Displaying and Formatting](#8-displaying-and-formatting)
9. [Format Token Reference](#9-format-token-reference)
10. [Querying and Comparing](#10-querying-and-comparing)
11. [Plugins](#11-plugins)
12. [Internationalization (i18n)](#12-internationalization-i18n)
13. [Common Tasks and Recipes](#13-common-tasks-and-recipes)
14. [Troubleshooting](#14-troubleshooting)
15. [FAQ](#15-faq)
16. [Quick Reference](#16-quick-reference)

---

## 1. Quick Start

Install the library and create your first date object.

```bash
npm install dayjs
```

```js
import dayjs from 'dayjs'

// The current date and time
dayjs().format('YYYY-MM-DD HH:mm:ss')
```

```text
'2019-03-06 15:25:00'
```

```js
// Parse a date, manipulate it, and display it — all chainable
dayjs('2018-08-08')          // parse
  .add(1, 'day')             // manipulate (returns a NEW object)
  .format('dddd, MMMM D, YYYY')
```

```text
'Thursday, August 9, 2018'
```

> [!NOTE]
> Calling `dayjs()` with no arguments returns an object for the current date and time. Every Day.js object wraps a native JavaScript `Date` internally but never exposes mutable state.

> [!TIP]
> Day.js objects are **immutable**. Methods like `add`, `subtract`, `set`, and `startOf` return a *new* object and leave the original untouched. Always capture the return value: `const tomorrow = today.add(1, 'day')`.

---

## 2. Why Day.js

- 🕒 **Familiar API** — methods and patterns mirror Moment.js, so migration is largely a drop-in replacement.
- 💪 **Immutable** — every operation returns a new instance; you cannot accidentally mutate a shared date.
- 🔥 **Chainable** — most methods return a Day.js object, so calls compose left to right.
- 🌐 **I18n support** — 140+ locales, each loaded on demand.
- 📦 **Tiny** — the core is roughly 2&nbsp;KB minified and gzipped; plugins and locales are opt-in.
- 👫 **Broad browser support** — built on the native `Date` object.

The core library deliberately ships only the most common functionality. Everything else — relative time, UTC, time zones, durations, custom parsing, ISO weeks, and more — is delivered as a [plugin](#11-plugins) you extend at runtime, so your bundle only carries what you use.

---

## 3. Installation

=== "npm"

    ```bash
    npm install dayjs --save
    ```

=== "Yarn"

    ```bash
    yarn add dayjs
    ```

=== "pnpm"

    ```bash
    pnpm add dayjs
    ```

=== "CDN"

    ```html
    <script src="https://unpkg.com/dayjs@1/dayjs.min.js"></script>
    <script>
      dayjs().format()
    </script>
    ```

### Importing

=== "ES Modules / bundlers"

    ```js
    import dayjs from 'dayjs'

    dayjs().format()
    ```

=== "CommonJS (Node.js)"

    ```js
    const dayjs = require('dayjs')

    dayjs().format()
    ```

=== "Browser global"

    When loaded from a `<script>` tag, the library is exposed as the global `dayjs`.

    ```html
    <script src="https://unpkg.com/dayjs@1/dayjs.min.js"></script>
    <script>
      console.log(dayjs().format())
    </script>
    ```

The package's `package.json` declares `"main": "dayjs.min.js"` and `"types": "index.d.ts"`, so both the runtime entry point and the bundled TypeScript declarations resolve automatically.

> [!IMPORTANT]
> TypeScript declarations are bundled with the package — there is no separate `@types/dayjs` to install. Type definitions for plugins live under `dayjs/plugin/<name>` and augment the core `Dayjs` interface automatically when you import them.

### Verifying the install

```js
import dayjs from 'dayjs'

console.log(dayjs.isDayjs(dayjs()))   // true
console.log(typeof dayjs().valueOf()) // 'number'
```

```text
true
number
```

---

## 4. Core Concepts

### Immutability

A Day.js object never changes after it is created. Manipulation methods build and return a fresh object:

```js
const original = dayjs('2019-01-25')
const changed = original.add(1, 'day')

original.format('YYYY-MM-DD')  // '2019-01-25' — unchanged
changed.format('YYYY-MM-DD')   // '2019-01-26'
```

```text
2019-01-25
2019-01-26
```

> [!WARNING]
> Because objects are immutable, a statement like `date.add(1, 'day')` on its own does nothing observable — the new object is discarded. You must use the return value.

If you genuinely need mutable behavior (for example when porting Moment.js code that relies on in-place mutation), the optional [`badMutable`](#badmutable) plugin restores it. It is named "bad" on purpose: mutation is discouraged.

### Chaining

Methods that return a Day.js object can be chained:

```js
dayjs()
  .set('hour', 9)
  .set('minute', 0)
  .add(7, 'day')
  .startOf('day')
  .format()
```

### Cloning

Passing a Day.js object to the `dayjs()` factory, or calling `.clone()`, produces an independent copy:

```js
const a = dayjs('2019-01-25')
const b = a.clone()       // explicit clone
const c = dayjs(a)        // cloning by passing to the constructor
```

> [!NOTE]
> You rarely need to clone manually. Since manipulation already returns new objects, cloning matters mainly when interoperating with the mutable `badMutable` plugin or when you want a defensive copy.

### Validity

Every object reports whether it holds a real date:

```js
dayjs('not a date').isValid()   // false
dayjs('2019-01-25').isValid()   // true
```

An invalid object formats to the string `Invalid Date` (unless the active locale overrides `invalidDate`), and its `toJSON()` returns `null`.

---

## 5. Parsing — Creating Day.js Objects

The `dayjs()` factory accepts several input types. The core library handles the most common cases; less common formats require a plugin.

### No argument — now

```js
dayjs()  // current date and time
```

### ISO 8601 string

The core parser recognizes ISO 8601 date and date-time strings:

```js
dayjs('2018-04-04T16:00:00.000Z')
dayjs('2018-04-04')
dayjs('2018-04')          // defaults to the 1st of the month
dayjs('2018-04-13 19:18') // space separator is accepted
```

Internally the core matches strings against this pattern (year, optional month, optional day, optional time components):

```text
YYYY[-/]MM[-/]DD[T or space]HH:mm:ss[.sss]
```

> [!IMPORTANT]
> The **core** parser only understands ISO 8601-like strings. To parse an arbitrary custom format such as `'31-12-2024'` or `'12/31/2024'`, enable the [`customParseFormat`](#customparseformat) plugin. Passing a non-ISO string to the core parser falls through to the native `new Date(string)`, whose behavior is implementation-dependent and may produce `Invalid Date`.

### Native Date object

```js
dayjs(new Date(2018, 8, 18))  // months are zero-indexed: month 8 = September
```

### Unix timestamp (milliseconds)

```js
dayjs(1318781876406)  // a number is treated as milliseconds since the epoch
```

### Unix timestamp (seconds)

Use the static `dayjs.unix()` helper for second-precision timestamps:

```js
dayjs.unix(1318781876)       // seconds → Day.js object
dayjs.unix(1318781876.721)   // fractional seconds are supported
```

### Cloning an existing object

```js
dayjs(dayjs('2019-01-25'))   // clones the passed object
```

### Null and undefined

```js
dayjs(null)       // Invalid Date — null is explicitly rejected
dayjs(undefined)  // current date and time (same as dayjs())
```

> [!CAUTION]
> `dayjs(null)` is **invalid** by design, while `dayjs(undefined)` returns the current time. Guard against accidentally passing `null` where you expected a date.

### Parsing table

| Input | Result |
|-------|--------|
| `dayjs()` | Current date and time |
| `dayjs('2018-04-04')` | Parsed from ISO 8601 string |
| `dayjs('2018-04')` | First day of the month |
| `dayjs(new Date())` | From a native `Date` |
| `dayjs(1318781876406)` | From milliseconds since epoch |
| `dayjs.unix(1318781876)` | From **seconds** since epoch |
| `dayjs(otherDayjs)` | Clone of an existing object |
| `dayjs(null)` | `Invalid Date` |
| `dayjs(undefined)` | Current date and time |

> [!TIP]
> Plugins extend parsing: [`customParseFormat`](#customparseformat) for custom string formats, [`arraySupport`](#arraysupport) for `dayjs([2010, 1, 14])`, [`objectSupport`](#objectsupport) for `dayjs({ year: 2010, month: 1 })`, [`utc`](#utc) for UTC-mode parsing, and [`bigIntSupport`](#bigintsupport) for BigInt timestamps.

---

## 6. Get and Set

### Getters

Call a unit method with no argument to read it:

```js
const d = dayjs('2019-01-25 12:34:56.789')

d.year()        // 2019
d.month()       // 0  (January — months are zero-indexed)
d.date()        // 25 (day of the month, 1–31)
d.day()         // 5  (day of the week, 0=Sunday … 6=Saturday)
d.hour()        // 12
d.minute()      // 34
d.second()      // 56
d.millisecond() // 789
```

> [!WARNING]
> `month()` is **zero-indexed** (January = 0, December = 11), matching the native `Date` API. `date()` is the day of the month (1–31); `day()` is the day of the week (0–6). These three are easy to confuse.

### Setters

Pass a value to return a new object with that unit changed:

```js
dayjs().year(2020)
dayjs().month(3)    // April
dayjs().date(1)
dayjs().hour(12)
dayjs().minute(0)
dayjs().second(30)
dayjs().millisecond(0)
```

Setters bubble over boundaries. Setting a date beyond the month length rolls into the next month; setting an hour past 23 rolls into the next day:

```js
dayjs('2019-01-25').date(33).format('YYYY-MM-DD')  // '2019-02-02'
```

### Generic `get` and `set`

`get(unit)` and `set(unit, value)` are equivalent to the named methods and accept long, short, and plural unit names (case-insensitive):

```js
dayjs().get('year')          // same as dayjs().year()
dayjs().set('date', 1)       // same as dayjs().date(1)
dayjs().set('month', 3)      // April
dayjs().set('second', 30)
```

```js
// These are all equivalent:
dayjs().set('day', 0)
dayjs().set('d', 0)
```

### Recognized units

| Unit | Short | Plural (with `pluralGetSet`) | Notes |
|------|-------|------------------------------|-------|
| `year` | `y` | `years` | |
| `month` | `M` | `months` | Zero-indexed (0–11) |
| `date` | `D` | `dates` | Day of month (1–31) |
| `day` | `d` | `days` | Day of week (0–6) |
| `hour` | `h` | `hours` | |
| `minute` | `m` | `minutes` | |
| `second` | `s` | `seconds` | |
| `millisecond` | `ms` | `milliseconds` | |

> [!NOTE]
> The plural getter/setter aliases (`years()`, `months()`, …) require the [`pluralGetSet`](#pluralgetset) plugin. The singular and short forms are always available.

### Days in month

```js
dayjs('2019-01-25').daysInMonth()  // 31
dayjs('2020-02-01').daysInMonth()  // 29 (leap year)
```

---

## 7. Manipulating Dates

All manipulation methods return a **new** Day.js object.

### Add

```js
dayjs().add(7, 'day')
dayjs().add(1, 'month')
dayjs().add(3, 'year')
dayjs().add(30, 'minute')
```

Units accept long, short, and (with `pluralGetSet`) plural forms:

```js
dayjs().add(1, 'd')   // same as 'day'
dayjs().add(1, 'M')   // month (capital M)
dayjs().add(1, 'm')   // minute (lowercase m)
```

> [!CAUTION]
> Token case matters for `add`/`subtract` units passed as short forms: `'M'` is **month** and `'m'` is **minute**, mirroring the format tokens. When in doubt, spell out the unit (`'month'`, `'minute'`).

### Subtract

```js
dayjs().subtract(7, 'year')
dayjs().subtract(1, 'month')
```

`subtract(n, unit)` is exactly `add(-n, unit)`.

### Start of / End of

Snap to the beginning or end of a unit:

```js
dayjs().startOf('year')    // Jan 1, 00:00:00.000
dayjs().startOf('month')   // 1st of month, 00:00:00.000
dayjs().startOf('week')    // first day of the week (locale-aware)
dayjs().startOf('day')     // 00:00:00.000
dayjs().endOf('month')     // last day of month, 23:59:59.999
dayjs().endOf('day')       // 23:59:59.999
```

> [!NOTE]
> `startOf('week')` respects the active locale's `weekStart` (e.g. Sunday for `en`, Monday for many European locales). For ISO weeks (always Monday), use the [`isoWeek`](#isoweek) plugin and `startOf('isoWeek')`.

### Chaining manipulations

```js
dayjs('2019-01-25')
  .add(1, 'day')
  .subtract(1, 'year')
  .startOf('month')
  .format('YYYY-MM-DD')      // '2018-01-01'
```

> [!TIP]
> Adding months or years clamps the day of month so it never overflows. `dayjs('2019-01-31').add(1, 'month')` yields the last day of February, not March 3.

---

## 8. Displaying and Formatting

### `format()`

With no template, `format()` returns an ISO 8601 string using the default template `YYYY-MM-DDTHH:mm:ssZ`:

```js
dayjs('2019-01-25').format()
```

```text
'2019-01-25T00:00:00+02:00'
```

Pass a template string of tokens:

```js
dayjs('2019-01-25').format('YYYY-MM-DD')              // '2019-01-25'
dayjs('2019-01-25').format('DD/MM/YYYY')              // '25/01/2019'
dayjs('2019-01-25').format('dddd, MMMM D, YYYY')      // 'Friday, January 25, 2019'
dayjs('2019-01-25 14:30').format('h:mm A')            // '2:30 PM'
```

### Escaping literal text

Wrap literal characters in square brackets so they are not interpreted as tokens:

```js
dayjs('2019-01-25').format('[Year] YYYY')   // 'Year 2019'
dayjs('2019-01-25').format('[Today is] dddd')
```

### `diff()` — difference between two dates

```js
const a = dayjs('2019-01-25')
const b = dayjs('2018-06-05')

a.diff(b)            // 20214000000  (milliseconds, default)
a.diff(b, 'month')   // 7
a.diff(b, 'day')     // 234
a.diff(b, 'year')    // 0
```

By default `diff` truncates toward zero (returns a whole number). Pass `true` as the third argument for a floating-point result:

```js
a.diff(b, 'month', true)   // 7.645... (fractional months)
```

### Native conversions

```js
dayjs('2019-01-25').valueOf()      // 1548381600000 — milliseconds since epoch
dayjs('2019-01-25').unix()         // 1548381600    — seconds since epoch (floored)
dayjs('2019-01-25').toDate()       // native Date object
dayjs('2019-01-25').toJSON()       // '2019-01-25T02:00:00.000Z' (ISO, or null if invalid)
dayjs('2019-01-25').toISOString()  // '2019-01-25T02:00:00.000Z'
dayjs('2019-01-25').toString()     // 'Fri, 25 Jan 2019 02:00:00 GMT'
```

> [!TIP]
> `valueOf()` returns **milliseconds**; `unix()` returns **seconds**. Use `unix()` when talking to APIs that expect Unix epoch seconds. Because `valueOf()` exists, you can also coerce with the unary plus operator: `+dayjs()`.

### UTC offset

```js
dayjs().utcOffset()   // offset in minutes, e.g. -300 for UTC-5
```

> [!NOTE]
> Relative time strings ("4 years ago", "in a minute"), calendar phrasing ("Today at 2:30 PM"), and named-token formats (`LLLL`, `Do`, `Q`, `X`) require plugins — see [`relativeTime`](#relativetime), [`calendar`](#calendar), [`localizedFormat`](#localizedformat), and [`advancedFormat`](#advancedformat).

---

## 9. Format Token Reference

These tokens are recognized by the **core** `format()` method. Output for name-based tokens (`MMMM`, `dddd`, `A`, …) depends on the active locale.

| Token | Example | Description |
|-------|---------|-------------|
| `YY` | `18` | Two-digit year |
| `YYYY` | `2018` | Four-digit year |
| `M` | `1`–`12` | Month, 1-indexed, no leading zero |
| `MM` | `01`–`12` | Month, 1-indexed, padded |
| `MMM` | `Jan` | Abbreviated month name |
| `MMMM` | `January` | Full month name |
| `D` | `1`–`31` | Day of month, no leading zero |
| `DD` | `01`–`31` | Day of month, padded |
| `d` | `0`–`6` | Day of week (0 = Sunday) |
| `dd` | `Su` | Minimal weekday name |
| `ddd` | `Sun` | Short weekday name |
| `dddd` | `Sunday` | Full weekday name |
| `H` | `0`–`23` | Hour, 24-hour, no leading zero |
| `HH` | `00`–`23` | Hour, 24-hour, padded |
| `h` | `1`–`12` | Hour, 12-hour, no leading zero |
| `hh` | `01`–`12` | Hour, 12-hour, padded |
| `m` | `0`–`59` | Minute, no leading zero |
| `mm` | `00`–`59` | Minute, padded |
| `s` | `0`–`59` | Second, no leading zero |
| `ss` | `00`–`59` | Second, padded |
| `SSS` | `000`–`999` | Millisecond, 3 digits |
| `A` | `AM` / `PM` | Meridiem, uppercase |
| `a` | `am` / `pm` | Meridiem, lowercase |
| `Z` | `+05:00` | UTC offset, with colon |
| `ZZ` | `+0500` | UTC offset, no colon |

> [!IMPORTANT]
> Additional tokens require plugins:
> - **`advancedFormat`** adds `Q`, `Do`, `gggg`, `GGGG`, `wo`, `w`/`ww`, `W`/`WW`, `k`/`kk`, `X`, `x`, `z`, `zzz`.
> - **`localizedFormat`** adds `LT`, `LTS`, `L`, `LL`, `LLL`, `LLLL` (and lowercase `l`, `ll`, `lll`, `llll`).

### Localized format tokens (`localizedFormat` plugin)

| Token | English output |
|-------|----------------|
| `LT` | `8:02 PM` |
| `LTS` | `8:02:18 PM` |
| `L` | `08/16/2018` |
| `LL` | `August 16, 2018` |
| `LLL` | `August 16, 2018 8:02 PM` |
| `LLLL` | `Thursday, August 16, 2018 8:02 PM` |

### Advanced format tokens (`advancedFormat` plugin)

| Token | Description |
|-------|-------------|
| `Q` | Quarter, 1–4 |
| `Do` | Day of month with ordinal (e.g. `1st`) |
| `w` / `ww` | Week of year (needs `weekOfYear`) |
| `W` / `WW` | ISO week of year (needs `isoWeek`) |
| `wo` | Week of year with ordinal |
| `gggg` | Week year (needs `weekYear`) |
| `GGGG` | ISO week year (needs `isoWeek`) |
| `k` / `kk` | Hour in 1–24 range |
| `X` | Unix timestamp in seconds |
| `x` | Unix timestamp in milliseconds |
| `z` / `zzz` | Time zone name (needs `timezone`) |

---

## 10. Querying and Comparing

The core provides three comparison methods plus validity checking. Several more comparisons are available via plugins.

### Core comparisons

```js
const d = dayjs('2019-01-25')

d.isBefore(dayjs('2019-02-01'))  // true
d.isAfter(dayjs('2019-01-01'))   // true
d.isSame(dayjs('2019-01-25'))    // true
d.isValid()                      // true
```

### Granular comparison with units

Pass a unit as the second argument to compare only down to that granularity:

```js
dayjs('2019-01-25').isSame('2019-01-30', 'month')  // true  (same month)
dayjs('2019-01-25').isBefore('2019-01-26', 'year') // false (same year)
dayjs('2019-01-25').isAfter('2018-12-31', 'year')  // true
```

> [!NOTE]
> Without a unit, comparisons are exact to the millisecond. With a unit, Day.js compares against the `startOf`/`endOf` that unit, so `isSame(other, 'month')` means "in the same calendar month."

### Comparison plugins

| Method | Plugin | Purpose |
|--------|--------|---------|
| `isSameOrBefore` | [`isSameOrBefore`](#issameorbefore) | `<=` comparison |
| `isSameOrAfter` | [`isSameOrAfter`](#issameorafter) | `>=` comparison |
| `isBetween` | [`isBetween`](#isbetween) | Range check with inclusivity control |
| `isToday` / `isTomorrow` / `isYesterday` | [`isToday`](#istoday-istomorrow-isyesterday) etc. | Relative-day checks |
| `isLeapYear` | [`isLeapYear`](#isleapyear) | Leap-year check |
| `isDayjs` (static) | core | Type check |

```js
dayjs.isDayjs(dayjs())     // true
dayjs.isDayjs(new Date())  // false
```

---

## 11. Plugins

Plugins extend Day.js with extra functionality. The pattern is always the same: **import** the core, **import** the plugin, **extend**, then use the new methods.

```js
import dayjs from 'dayjs'
import relativeTime from 'dayjs/plugin/relativeTime'

dayjs.extend(relativeTime)

dayjs('1999-01-01').fromNow()   // now available
```

> [!IMPORTANT]
> `dayjs.extend(plugin)` installs a plugin **once** per process — calling it again with the same plugin is a no-op. Call `extend` during app startup, before you use the plugin's methods. Some plugins accept an option object as a second argument: `dayjs.extend(plugin, options)`.

> [!TIP]
> Only extend the plugins you actually use. Each plugin you skip is code that never enters your bundle — this is the whole reason the core stays around 2&nbsp;KB.

The 37 official plugins follow.

### advancedFormat

Adds extra format tokens to `format()`: `Q`, `Do`, `gggg`, `GGGG`, `wo`, `w`, `ww`, `W`, `WW`, `k`, `kk`, `X`, `x`, `z`, `zzz`.

```js
import advancedFormat from 'dayjs/plugin/advancedFormat'
dayjs.extend(advancedFormat)

dayjs('2019-01-25').format('Q Do k X')  // e.g. '1 25th 24 1548381600'
```

> [!NOTE]
> Some advanced tokens depend on other plugins: `w`/`wo` need `weekOfYear`, `W`/`GGGG` need `isoWeek`, `gggg` needs `weekYear`, and `z`/`zzz` need `timezone`.

### arraySupport

Lets the `dayjs()` factory accept an array `[year, month, day, hour, minute, second, millisecond]` (month is zero-indexed).

```js
import arraySupport from 'dayjs/plugin/arraySupport'
dayjs.extend(arraySupport)

dayjs([2010, 1, 14, 15, 25, 50, 125])  // Feb 14 2010, 15:25:50.125
dayjs([2010])                          // a single element is parsed as a year string
```

### badMutable

Makes Day.js objects **mutable** — manipulation methods modify the original in place instead of returning a new object. Restores Moment.js-style mutation for migration.

```js
import badMutable from 'dayjs/plugin/badMutable'
dayjs.extend(badMutable)

const d = dayjs('2019-01-25')
d.add(1, 'day')                  // d itself is now mutated
d.format('YYYY-MM-DD')           // '2019-01-26'
```

> [!CAUTION]
> The name is a warning. Mutability defeats the safety guarantee that makes Day.js predictable. Use this only to ease a migration, and remove it once your code no longer relies on mutation.

### bigIntSupport

Allows BigInt values as timestamps, both in the factory and in `dayjs.unix()`.

```js
import bigIntSupport from 'dayjs/plugin/bigIntSupport'
dayjs.extend(bigIntSupport)

dayjs(1318781876406n)
dayjs.unix(1318781876n)
```

### buddhistEra

Adds the `BBBB` and `BB` format tokens for the Buddhist Era (year + 543).

```js
import buddhistEra from 'dayjs/plugin/buddhistEra'
dayjs.extend(buddhistEra)

dayjs('2019-01-25').format('BBBB-MM-DD')  // '2562-01-25'
dayjs('2019-01-25').format('BB')          // '62'
```

### calendar

Adds `calendar()` for human-friendly relative phrasing within about a week of a reference time.

```js
import calendar from 'dayjs/plugin/calendar'
dayjs.extend(calendar)

dayjs().calendar()                 // 'Today at 2:30 PM'
dayjs().add(1, 'day').calendar()   // 'Tomorrow at 2:30 PM'
dayjs().subtract(1, 'day').calendar()
```

You can pass a reference time and custom format strings:

```js
dayjs().calendar(dayjs('2008-01-01'), {
  sameDay: '[Today at] h:mm A',
  nextDay: '[Tomorrow at] h:mm A',
  nextWeek: 'dddd [at] h:mm A',
  lastDay: '[Yesterday at] h:mm A',
  lastWeek: '[Last] dddd [at] h:mm A',
  sameElse: 'MM/DD/YYYY'
})
```

The default format keys are `sameDay`, `nextDay`, `nextWeek`, `lastDay`, `lastWeek`, and `sameElse`.

### customParseFormat

Parses date strings that match a supplied format. This is the plugin you need for any non-ISO input.

```js
import customParseFormat from 'dayjs/plugin/customParseFormat'
dayjs.extend(customParseFormat)

dayjs('05/02/69 1:02:03 PM -05:00', 'MM/DD/YY H:mm:ss A Z')
dayjs('2018 5月', 'YYYY M月')
dayjs('31-12-2024', 'DD-MM-YYYY')
```

Strict mode (third argument `true`) rejects input that doesn't match the format exactly:

```js
dayjs('1970-00-00', 'YYYY-MM-DD').isValid()        // true (lenient)
dayjs('1970-00-00', 'YYYY-MM-DD', true).isValid()  // false (strict)
```

Pass a locale, or an array of formats to try in order:

```js
dayjs('2018 三月', 'YYYY MMMM', 'zh-cn')
dayjs('2012-05-28', ['YYYY-MM-DD', 'YYYY/MM/DD'])
```

Supported parsing tokens include `YY`, `YYYY`, `M`, `MM`, `MMM`, `MMMM`, `D`, `DD`, `Do`, `H`/`HH`, `h`/`hh`, `m`/`mm`, `s`/`ss`, `S`/`SS`/`SSS`, `Z`/`ZZ`, `A`/`a`, `Q`, `w`/`ww`, and `X`/`x`. A `parseTwoDigitYear` option customizes how two-digit years are interpreted.

> [!WARNING]
> The format tokens here are for **parsing** input, not formatting output. To both parse a custom format and re-display it, combine `customParseFormat` with `format()`.

### dayOfYear

Adds `dayOfYear()` to get or set the day of the year (1–366).

```js
import dayOfYear from 'dayjs/plugin/dayOfYear'
dayjs.extend(dayOfYear)

dayjs('2010-01-01').dayOfYear()    // 1
dayjs('2010-12-31').dayOfYear()    // 365
dayjs('2010-01-01').dayOfYear(200) // sets to the 200th day
```

### devHelper

A development-only plugin that prints `console.warn` hints for common mistakes — passing a millisecond timestamp as a string, passing a 4-digit year as a number, using a custom parse format without `customParseFormat`, or calling `diff()` with an invalid date.

```js
import devHelper from 'dayjs/plugin/devHelper'
dayjs.extend(devHelper)
```

> [!NOTE]
> The warnings are suppressed when `process.env.NODE_ENV === 'production'`, so this plugin is safe to leave in code that gets a production build, but it is most useful during development.

### duration

Adds a `Duration` object for representing lengths of time (independent of any specific date), plus `dayjs.duration()` and `dayjs.isDuration()`.

```js
import duration from 'dayjs/plugin/duration'
dayjs.extend(duration)

dayjs.duration(100)                      // 100 milliseconds
dayjs.duration(2, 'days')
dayjs.duration({ days: 2, hours: 12 })
dayjs.duration('P1Y2M3DT4H5M6S')         // ISO 8601 duration string

const d = dayjs.duration(2, 'days')
d.asHours()       // 48
d.days()          // 2
d.toISOString()   // 'P2D'
d.format('D [days]')
```

With `relativeTime` also extended, durations can be humanized, and durations can be added to or subtracted from a date:

```js
dayjs.duration(1, 'minutes').humanize()   // 'a minute' (needs relativeTime)
dayjs('2019-01-01').add(dayjs.duration(1, 'month'))
```

Available accessors: `milliseconds`/`asMilliseconds`, `seconds`/`asSeconds`, `minutes`/`asMinutes`, `hours`/`asHours`, `days`/`asDays`, `weeks`/`asWeeks`, `months`/`asMonths`, `years`/`asYears`, plus `get(unit)`, `as(unit)`, `add`, `subtract`, `clone`, `locale`, `format`, `toJSON`, and `toISOString`.

### isBetween

Adds `isBetween()` to test whether a date falls within a range, with inclusivity control.

```js
import isBetween from 'dayjs/plugin/isBetween'
dayjs.extend(isBetween)

dayjs('2010-10-20').isBetween('2010-10-19', '2010-10-25')                 // true
dayjs('2010-10-20').isBetween('2010-10-19', '2010-10-25', 'year')         // false
dayjs('2016-10-30').isBetween('2016-01-01', '2016-10-30', null, '[]')     // inclusive
```

The fourth argument controls inclusivity: `'()'` (default, both exclusive), `'[]'` (both inclusive), `'[)'`, or `'(]'`.

### isLeapYear

Adds `isLeapYear()`.

```js
import isLeapYear from 'dayjs/plugin/isLeapYear'
dayjs.extend(isLeapYear)

dayjs('2000-01-01').isLeapYear()  // true
dayjs('2019-01-01').isLeapYear()  // false
```

### isMoment

Adds the static `dayjs.isMoment()` (an alias of `dayjs.isDayjs`) to ease migration of code that called `moment.isMoment()`.

```js
import isMoment from 'dayjs/plugin/isMoment'
dayjs.extend(isMoment)

dayjs.isMoment(dayjs())  // true
```

### isoWeek

Adds ISO 8601 week support: `isoWeek()`, `isoWeekday()`, `isoWeekYear()`, and `startOf('isoWeek')`/`endOf('isoWeek')`. ISO weeks always start on Monday.

```js
import isoWeek from 'dayjs/plugin/isoWeek'
dayjs.extend(isoWeek)

dayjs('2019-01-25').isoWeek()       // ISO week number
dayjs('2019-01-25').isoWeekday()    // 1 (Mon) – 7 (Sun)
dayjs('2019-01-25').startOf('isoWeek')
```

### isoWeeksInYear

Adds `isoWeeksInYear()`, returning 52 or 53.

```js
import isoWeeksInYear from 'dayjs/plugin/isoWeeksInYear'
import isLeapYear from 'dayjs/plugin/isLeapYear'
dayjs.extend(isLeapYear)   // required dependency
dayjs.extend(isoWeeksInYear)

dayjs('2004-01-01').isoWeeksInYear()  // 53
```

> [!NOTE]
> `isoWeeksInYear` relies on `isLeapYear`; extend both.

### isSameOrAfter

Adds `isSameOrAfter()` (a `>=` comparison).

```js
import isSameOrAfter from 'dayjs/plugin/isSameOrAfter'
dayjs.extend(isSameOrAfter)

dayjs('2010-10-20').isSameOrAfter('2010-10-19', 'year')  // true
```

### isSameOrBefore

Adds `isSameOrBefore()` (a `<=` comparison).

```js
import isSameOrBefore from 'dayjs/plugin/isSameOrBefore'
dayjs.extend(isSameOrBefore)

dayjs('2010-10-20').isSameOrBefore('2010-10-21')  // true
```

### isToday, isTomorrow, isYesterday

Three small plugins that each add one boolean method, comparing the calendar day against the current day.

```js
import isToday from 'dayjs/plugin/isToday'
import isTomorrow from 'dayjs/plugin/isTomorrow'
import isYesterday from 'dayjs/plugin/isYesterday'
dayjs.extend(isToday)
dayjs.extend(isTomorrow)
dayjs.extend(isYesterday)

dayjs().isToday()                  // true
dayjs().add(1, 'day').isTomorrow() // true
dayjs().subtract(1, 'day').isYesterday()  // true
```

### localeData

Exposes locale data (month names, weekday names, meridiem, ordinal, first day of week, long date formats) through instance and static `localeData()` accessors.

```js
import localeData from 'dayjs/plugin/localeData'
dayjs.extend(localeData)

dayjs.months()             // ['January', 'February', …]
dayjs.weekdaysShort()      // ['Sun', 'Mon', …]
dayjs().localeData().firstDayOfWeek()
```

### localizedFormat

Adds locale-aware format tokens `LT`, `LTS`, `L`, `LL`, `LLL`, `LLLL` (and lowercase `l`, `ll`, `lll`, `llll`).

```js
import localizedFormat from 'dayjs/plugin/localizedFormat'
dayjs.extend(localizedFormat)

dayjs('2019-01-25 22:00').format('LLLL')  // 'Friday, January 25, 2019 10:00 PM'
dayjs('2019-01-25').format('L LT')
```

### minMax

Adds static `dayjs.max()` and `dayjs.min()` to find the latest/earliest of several dates.

```js
import minMax from 'dayjs/plugin/minMax'
dayjs.extend(minMax)

dayjs.max(dayjs(), dayjs('2018-01-01'), dayjs('2019-01-01'))
dayjs.min([dayjs(), dayjs('2018-01-01'), dayjs('2019-01-01')])  // array form
```

Both accept either a list of arguments or a single array.

### negativeYear

Handles parsing of negative-year strings (years BCE), e.g. `'-2020-01-01'`.

```js
import negativeYear from 'dayjs/plugin/negativeYear'
dayjs.extend(negativeYear)

dayjs('-1000-01-01').year()  // -1000
```

### objectSupport

Lets the factory, `set`, `add`, and `subtract` accept plain objects of units.

```js
import objectSupport from 'dayjs/plugin/objectSupport'
dayjs.extend(objectSupport)

dayjs({ year: 2010, month: 1, day: 12 })   // month is zero-indexed
dayjs().set({ hour: 9, minute: 0 })
dayjs().add({ days: 7, months: 1 })
```

### pluralGetSet

Adds plural-form getter/setter aliases: `years()`, `months()`, `dates()`, `weeks()`, `days()`, `hours()`, `minutes()`, `seconds()`, `milliseconds()`, `isoWeeks()`, `quarters()`.

```js
import pluralGetSet from 'dayjs/plugin/pluralGetSet'
dayjs.extend(pluralGetSet)

dayjs().years()       // same as dayjs().year()
dayjs().minutes(30)   // same as dayjs().minute(30)
```

### preParsePostFormat

A hook plugin that runs the active locale's `preparse` function on input strings before parsing and its `postformat` function on output strings after formatting — used mainly for locales with non-Latin numerals (e.g. Arabic-Indic digits).

```js
import preParsePostFormat from 'dayjs/plugin/preParsePostFormat'
dayjs.extend(preParsePostFormat)
```

### quarterOfYear

Adds `quarter()` to get or set the quarter, plus `'quarter'` support in `add`, `subtract`, `startOf`, and `endOf`.

```js
import quarterOfYear from 'dayjs/plugin/quarterOfYear'
dayjs.extend(quarterOfYear)

dayjs('2010-04-01').quarter()           // 2
dayjs('2010-04-01').add(1, 'quarter')
dayjs('2010-05-01').startOf('quarter')  // April 1
```

### relativeTime

Adds human-friendly relative phrasing: `fromNow()`, `from()`, `toNow()`, `to()`.

```js
import relativeTime from 'dayjs/plugin/relativeTime'
dayjs.extend(relativeTime)

dayjs('1999-01-01').fromNow()              // 'over a year ago' style phrasing
dayjs('2000-01-01').from(dayjs('2000-01-02'))  // 'a day ago'
dayjs().toNow()
```

Pass `true` to omit the suffix ("4 years" instead of "4 years ago"):

```js
dayjs('1999-01-01').fromNow(true)   // omits 'ago'
```

You can customize rounding and thresholds when extending:

```js
dayjs.extend(relativeTime, {
  thresholds: [
    { l: 's', r: 1 },
    { l: 'm', r: 1 },
    { l: 'mm', r: 59, d: 'minute' }
    // …
  ],
  rounding: Math.floor
})
```

Default phrasings include `a few seconds`, `a minute`, `%d minutes`, `an hour`, `%d hours`, `a day`, `%d days`, `a month`, `%d months`, `a year`, `%d years`, with `in %s` / `%s ago` for future/past.

### timezone

Adds IANA time-zone support on top of the [`utc`](#utc) plugin (which it requires): `.tz()`, `.offsetName()`, `dayjs.tz()`, `dayjs.tz.guess()`, and `dayjs.tz.setDefault()`.

```js
import utc from 'dayjs/plugin/utc'
import timezone from 'dayjs/plugin/timezone'
dayjs.extend(utc)
dayjs.extend(timezone)   // depends on utc

dayjs('2014-06-01 12:00').tz('America/New_York')
dayjs.tz('2014-06-01 12:00', 'America/New_York')
dayjs.tz.guess()                 // the user's IANA zone
dayjs.tz.setDefault('America/New_York')
dayjs().tz().offsetName('long')  // e.g. 'Eastern Daylight Time'
```

> [!IMPORTANT]
> `timezone` requires the `utc` plugin and uses the runtime's built-in `Intl.DateTimeFormat`. Zone lookups are cached internally for performance. Extend `utc` **before** `timezone`.

### toArray

Adds `toArray()` returning `[year, month, date, hour, minute, second, millisecond]` (month zero-indexed).

```js
import toArray from 'dayjs/plugin/toArray'
dayjs.extend(toArray)

dayjs('2019-01-25').toArray()  // [2019, 0, 25, 0, 0, 0, 0]
```

### toObject

Adds `toObject()` returning `{ years, months, date, hours, minutes, seconds, milliseconds }`.

```js
import toObject from 'dayjs/plugin/toObject'
dayjs.extend(toObject)

dayjs('2019-01-25').toObject()
// { years: 2019, months: 0, date: 25, hours: 0, minutes: 0, seconds: 0, milliseconds: 0 }
```

### updateLocale

Adds static `dayjs.updateLocale()` to override specific properties of an already-loaded locale without redefining the whole thing.

```js
import updateLocale from 'dayjs/plugin/updateLocale'
dayjs.extend(updateLocale)

dayjs.updateLocale('en', {
  weekStart: 1,
  months: ['Jan', 'Feb', /* … */]
})
```

> [!NOTE]
> The target locale must already be loaded; `updateLocale` merges your changes into it and returns `undefined` if the locale isn't found.

### utc

Adds UTC mode: `dayjs.utc()`, `.utc()`, `.local()`, `.isUTC()`, and an overloaded `.utcOffset(offset)` setter.

```js
import utc from 'dayjs/plugin/utc'
dayjs.extend(utc)

dayjs.utc('2019-01-25T02:00:00.000Z').format()  // UTC ISO output
dayjs('2019-01-25').utc().format()
dayjs.utc().local()                              // back to local time
dayjs().utc().isUTC()                            // true
dayjs().utcOffset(8)                             // set offset to +8 hours
```

UTC-mode objects format with a default template of `YYYY-MM-DDTHH:mm:ss[Z]` and read their parts via the native `getUTC*` methods.

### weekday

Adds `weekday()` — a locale-aware day-of-week getter/setter where 0 is the *first day of the week for the active locale* (unlike `day()`, where 0 is always Sunday).

```js
import weekday from 'dayjs/plugin/weekday'
dayjs.extend(weekday)

dayjs().weekday()    // 0 = first day of the locale's week
dayjs().weekday(0)   // set to the first day of this week
```

### weekOfYear

Adds `week()` to get or set the week of the year (locale-aware), plus the `weeks()` alias.

```js
import weekOfYear from 'dayjs/plugin/weekOfYear'
dayjs.extend(weekOfYear)

dayjs('2019-06-01').week()    // week number
dayjs('2019-06-01').week(1)   // set to week 1
```

### weekYear

Adds `weekYear()`, the year that owns the current locale week. Requires `weekOfYear`.

```js
import weekOfYear from 'dayjs/plugin/weekOfYear'
import weekYear from 'dayjs/plugin/weekYear'
dayjs.extend(weekOfYear)
dayjs.extend(weekYear)

dayjs('2019-12-31').weekYear()
```

### Plugin dependency cheat sheet

| Plugin | Requires first |
|--------|----------------|
| `timezone` | `utc` |
| `weekYear` | `weekOfYear` |
| `isoWeeksInYear` | `isLeapYear` |
| `advancedFormat` `w`/`W`/`gggg`/`z` tokens | `weekOfYear` / `isoWeek` / `weekYear` / `timezone` |
| `duration` humanize | `relativeTime` |

---

## 12. Internationalization (i18n)

Day.js ships **143 locale files** (English is built in). Locales are loaded on demand, so they never bloat your bundle unless you import them.

### Loading and switching locales

Import a locale, then set it globally or per-object:

```js
import dayjs from 'dayjs'
import 'dayjs/locale/zh-cn'   // load the locale (registers it)

dayjs.locale('zh-cn')                  // set globally
dayjs('2018-08-08').format('YYYY年MM月DD日')
```

Per-object locale (does not change the global default):

```js
import 'dayjs/locale/es'

dayjs().locale('es').format('dddd')    // Spanish weekday, global locale unchanged
```

Read the current global locale:

```js
dayjs.locale()   // 'en'
```

> [!TIP]
> `dayjs.locale('xx')` changes the **global** default for new objects. `someDate.locale('xx')` returns a new object using that locale and leaves the global default alone. Prefer the per-object form in libraries so you don't surprise the host application.

### Defining a custom locale

A locale object provides names and formatting rules:

```js
dayjs.locale('custom', {
  name: 'custom',
  weekdays: ['Sunday', 'Monday', /* … */],
  months: ['January', 'February', /* … */],
  weekStart: 1,           // Monday
  yearStart: 4,           // first week containing Jan 4
  ordinal: (n) => `${n}.`,
  formats: {
    LT: 'HH:mm',
    L: 'DD/MM/YYYY',
    LL: 'D MMMM YYYY'
  }
})
```

The English locale is intentionally minimal — it omits `weekdaysShort`, `weekdaysMin`, and `monthsShort` because `format()` derives short names by slicing the full ones when a locale doesn't supply explicit short forms.

### Tweaking an existing locale

Use the [`updateLocale`](#updatelocale) plugin to override only certain fields (for example, to make the week start on Monday):

```js
import updateLocale from 'dayjs/plugin/updateLocale'
dayjs.extend(updateLocale)
dayjs.updateLocale('en', { weekStart: 1 })
```

### Locale object fields

| Field | Purpose |
|-------|---------|
| `name` | Locale identifier (e.g. `'zh-cn'`) |
| `weekdays` | Full weekday names (Sun → Sat) |
| `weekdaysShort` | Short weekday names (optional) |
| `weekdaysMin` | Minimal weekday names (optional) |
| `months` | Full month names |
| `monthsShort` | Short month names (optional) |
| `weekStart` | First day of the week (0 = Sunday) |
| `yearStart` | Day-of-Jan that anchors week 1 |
| `ordinal` | Function turning a number into an ordinal string |
| `formats` | Long date formats (`LT`, `L`, `LL`, …) for `localizedFormat` |
| `relativeTime` | Phrasing map for `relativeTime` |
| `meridiem` | Function producing AM/PM equivalents |
| `calendar` | Phrasing map for the `calendar` plugin |

---

## 13. Common Tasks and Recipes

### Format the current date

```js
dayjs().format('YYYY-MM-DD HH:mm:ss')
```

### Get the start and end of today

```js
dayjs().startOf('day')   // 00:00:00.000
dayjs().endOf('day')     // 23:59:59.999
```

### Add business-friendly offsets

```js
dayjs().add(2, 'week').format('YYYY-MM-DD')
dayjs().subtract(1, 'month').endOf('month').format('YYYY-MM-DD')
```

### Difference in days between two dates

```js
dayjs('2024-12-31').diff('2024-01-01', 'day')   // 365
```

### "Time ago" label

```js
import relativeTime from 'dayjs/plugin/relativeTime'
dayjs.extend(relativeTime)

dayjs(post.createdAt).fromNow()   // 'a few seconds ago', '2 hours ago', …
```

### Parse a non-ISO string

```js
import customParseFormat from 'dayjs/plugin/customParseFormat'
dayjs.extend(customParseFormat)

dayjs('31/12/2024', 'DD/MM/YYYY').format('YYYY-MM-DD')   // '2024-12-31'
```

### Work in a specific time zone

```js
import utc from 'dayjs/plugin/utc'
import timezone from 'dayjs/plugin/timezone'
dayjs.extend(utc); dayjs.extend(timezone)

dayjs.tz('2024-06-01 09:00', 'America/New_York').format()
```

### Validate user input

```js
import customParseFormat from 'dayjs/plugin/customParseFormat'
dayjs.extend(customParseFormat)

function isValidDate(input) {
  return dayjs(input, 'YYYY-MM-DD', true).isValid()   // strict mode
}
```

### Iterate over a date range

```js
function eachDay(start, end) {
  const days = []
  let cursor = dayjs(start)
  const last = dayjs(end)
  while (cursor.isBefore(last) || cursor.isSame(last, 'day')) {
    days.push(cursor.format('YYYY-MM-DD'))
    cursor = cursor.add(1, 'day')
  }
  return days
}
```

> [!TIP]
> Because objects are immutable, range loops must **reassign** the cursor (`cursor = cursor.add(1, 'day')`). A bare `cursor.add(1, 'day')` would loop forever.

---

## 14. Troubleshooting

### Error: `Invalid Date` returned from `dayjs()`

**Cause:** The input couldn't be parsed — most often a non-ISO string passed to the core parser, or `dayjs(null)`.

**Solution:** Verify the input matches ISO 8601, or enable `customParseFormat` and pass the format explicitly. Check with `.isValid()` before using the result.

**Prevention:** Validate user-supplied dates with strict-mode `customParseFormat`. Remember `dayjs(null)` is intentionally invalid while `dayjs(undefined)` is "now."

### My `add`/`subtract`/`set` call seems to do nothing

**Cause:** Day.js is immutable; these methods return a new object and leave the original unchanged.

**Solution:** Assign the result: `date = date.add(1, 'day')`.

**Prevention:** Treat every Day.js object as read-only. If you truly need mutation, the `badMutable` plugin exists — but reassignment is the idiomatic fix.

### `month()` returns the wrong number

**Cause:** Months are **zero-indexed** (January = 0). This matches native `Date`.

**Solution:** Add 1 for human display, or format with `MM`/`MMMM` which are 1-indexed/named.

**Prevention:** Use `format('M')` (1-indexed) for output rather than `month() + 1` string-building.

### Error: `fromNow is not a function`

**Cause:** The `relativeTime` plugin wasn't extended before use.

**Solution:**

```js
import relativeTime from 'dayjs/plugin/relativeTime'
dayjs.extend(relativeTime)
```

**Prevention:** Centralize all `dayjs.extend(...)` calls in one startup module that runs before any date logic.

### Error: `tz is not a function`

**Cause:** The `timezone` plugin (and its required `utc` plugin) weren't extended.

**Solution:** Extend `utc` first, then `timezone`.

**Prevention:** Follow the [plugin dependency cheat sheet](#plugin-dependency-cheat-sheet) — `timezone` always needs `utc`.

### Console warning: "To parse a date-time string … you should enable customParseFormat plugin first"

**Cause:** You passed a format string as the second argument without extending `customParseFormat`. The message comes from the `devHelper` plugin.

**Solution:** Extend `customParseFormat`.

**Prevention:** These warnings only appear with `devHelper` in non-production builds; treat them as a checklist before shipping.

### Console warning: "Guessing you may want to use locale … you have to load it before using it"

**Cause:** You called `dayjs.locale('xx')` without first importing `dayjs/locale/xx`.

**Solution:** `import 'dayjs/locale/xx'` before setting the locale.

**Prevention:** Import each locale module you intend to activate.

### `startOf('week')` starts on the wrong day

**Cause:** Week start is locale-dependent (`weekStart`). The default `en` locale starts on Sunday.

**Solution:** Switch locale, override with `updateLocale({ weekStart: 1 })`, or use `startOf('isoWeek')` (always Monday) via the `isoWeek` plugin.

**Prevention:** Decide on calendar vs. ISO week semantics up front.

### A custom-format string parses but re-formats incorrectly

**Cause:** `customParseFormat` tokens are for **reading** input; `format()` tokens are for **writing** output. They are separate steps.

**Solution:** `dayjs(input, parseFormat).format(displayFormat)`.

**Prevention:** Keep parse format and display format as distinct variables.

### Two-digit years parse to the wrong century

**Cause:** The default rule maps `YY > 68` to the 1900s and otherwise to the 2000s.

**Solution:** Supply a `parseTwoDigitYear` function in the `customParseFormat` options.

**Prevention:** Prefer four-digit years (`YYYY`) in stored data.

### Duration `humanize()` throws or returns nothing

**Cause:** `humanize()` depends on `relativeTime`.

**Solution:** Extend both `duration` and `relativeTime`.

**Prevention:** See the dependency cheat sheet.

### `diff` returns 0 for dates that differ

**Cause:** `diff` truncates to a whole number by default, so sub-unit differences round toward zero.

**Solution:** Pass `true` as the third argument for a floating-point result, or use a smaller unit.

**Prevention:** Choose the unit and float flag deliberately for the precision you need.

---

## 15. FAQ

**Q: Is Day.js a drop-in replacement for Moment.js?**
A: For most common operations, yes — the API is intentionally Moment-compatible. Some Moment features live behind plugins (UTC, time zones, durations, custom parsing) that you extend on demand. Mutation-dependent Moment code needs the `badMutable` plugin or a refactor, since Day.js is immutable by default.

**Q: How big is Day.js really?**
A: The core is roughly 2&nbsp;KB minified and gzipped. Plugins and locales add only what you import, so a typical app stays small.

**Q: Do I need to install `@types/dayjs` for TypeScript?**
A: No. Type declarations ship with the package (`index.d.ts`), and plugin types under `dayjs/plugin/*` augment the core types automatically when imported.

**Q: Why is `month()` zero-indexed?**
A: To match the native JavaScript `Date` API. Use the `MM`/`MMMM` format tokens for human-readable, 1-indexed output.

**Q: How do I get the current Unix timestamp?**
A: `dayjs().unix()` for seconds, `dayjs().valueOf()` for milliseconds.

**Q: How do I parse a date in a specific format?**
A: Extend `customParseFormat` and pass the format string: `dayjs('31-12-2024', 'DD-MM-YYYY')`.

**Q: How do I display "3 hours ago"?**
A: Extend `relativeTime` and call `.fromNow()`.

**Q: How do I work with time zones?**
A: Extend `utc` then `timezone`, and use `.tz('Area/City')` or `dayjs.tz(...)`.

**Q: Are Day.js objects safe to share across my app?**
A: Yes — they're immutable, so no caller can change an object another part of your code holds (unless `badMutable` is active).

**Q: How many locales are available?**
A: 143 locale files ship with the package; English is built in and the rest load on demand via `import 'dayjs/locale/<name>'`.

**Q: How do I make the week start on Monday?**
A: Use a locale whose `weekStart` is 1, override with `updateLocale('en', { weekStart: 1 })`, or use the `isoWeek` plugin's `startOf('isoWeek')`.

**Q: What's the difference between `day()`, `date()`, and `weekday()`?**
A: `day()` is the day of week (0 = Sunday, always). `date()` is the day of the month (1–31). `weekday()` (plugin) is the day of week relative to the locale's first day.

**Q: How do I add a quarter or a week?**
A: Weeks work in the core (`add(1, 'week')`). Quarters need the `quarterOfYear` plugin (`add(1, 'quarter')`).

**Q: Can I represent a length of time, not a moment?**
A: Yes — the `duration` plugin provides `dayjs.duration(...)` objects with `asHours()`, `asDays()`, ISO output, and more.

**Q: My loop over a date range never ends — why?**
A: You're calling `cursor.add(1, 'day')` without reassigning. Immutability means you must write `cursor = cursor.add(1, 'day')`.

---

## 16. Quick Reference

### Core static methods

| Method | Purpose |
|--------|---------|
| `dayjs(input?)` | Create an object (now, string, Date, ms number, or clone) |
| `dayjs.unix(seconds)` | Create from a seconds timestamp |
| `dayjs.extend(plugin, opts?)` | Install a plugin (once) |
| `dayjs.locale(name?, obj?)` | Get or set the global locale |
| `dayjs.isDayjs(value)` | Type check |

### Core instance methods

| Method | Returns |
|--------|---------|
| `clone()` | New identical object |
| `isValid()` | Boolean |
| `year/month/date/day/hour/minute/second/millisecond()` | Getter (no arg) / setter (value) |
| `get(unit)` / `set(unit, value)` | Generic getter / setter |
| `add(n, unit)` / `subtract(n, unit)` | New shifted object |
| `startOf(unit)` / `endOf(unit)` | New snapped object |
| `format(template?)` | String |
| `diff(date?, unit?, float?)` | Number |
| `valueOf()` / `unix()` | Milliseconds / seconds |
| `daysInMonth()` | Number |
| `toDate()` / `toJSON()` / `toISOString()` / `toString()` | Native Date / strings |
| `utcOffset()` | Minutes |
| `isBefore/isSame/isAfter(date, unit?)` | Boolean |
| `locale(name?, obj?)` | Locale string / new localized object |

### Plugins at a glance

| Plugin | Adds |
|--------|------|
| `advancedFormat` | Extra format tokens (`Q`, `Do`, `X`, …) |
| `arraySupport` | Array input to the factory |
| `badMutable` | In-place mutation |
| `bigIntSupport` | BigInt timestamps |
| `buddhistEra` | `BBBB`/`BB` tokens |
| `calendar` | `calendar()` |
| `customParseFormat` | Custom-format parsing |
| `dayOfYear` | `dayOfYear()` |
| `devHelper` | Dev-time warnings |
| `duration` | `dayjs.duration()` objects |
| `isBetween` | `isBetween()` |
| `isLeapYear` | `isLeapYear()` |
| `isMoment` | `dayjs.isMoment()` |
| `isoWeek` | ISO week methods |
| `isoWeeksInYear` | `isoWeeksInYear()` |
| `isSameOrAfter` | `isSameOrAfter()` |
| `isSameOrBefore` | `isSameOrBefore()` |
| `isToday` / `isTomorrow` / `isYesterday` | Relative-day checks |
| `localeData` | Locale data accessors |
| `localizedFormat` | `L`/`LL`/`LLLL` tokens |
| `minMax` | `dayjs.max()` / `dayjs.min()` |
| `negativeYear` | Negative-year parsing |
| `objectSupport` | Object input to factory/set/add |
| `pluralGetSet` | Plural getter/setter aliases |
| `preParsePostFormat` | Locale preparse/postformat hooks |
| `quarterOfYear` | `quarter()` and `'quarter'` unit |
| `relativeTime` | `fromNow()` / `from()` / `to()` / `toNow()` |
| `timezone` | IANA time-zone support |
| `toArray` | `toArray()` |
| `toObject` | `toObject()` |
| `updateLocale` | `dayjs.updateLocale()` |
| `utc` | UTC mode |
| `weekday` | Locale-relative weekday |
| `weekOfYear` | `week()` |
| `weekYear` | `weekYear()` |

### Setup template

```js
import dayjs from 'dayjs'

// Plugins
import relativeTime from 'dayjs/plugin/relativeTime'
import customParseFormat from 'dayjs/plugin/customParseFormat'
import utc from 'dayjs/plugin/utc'
import timezone from 'dayjs/plugin/timezone'

// Locale (optional)
import 'dayjs/locale/en'

dayjs.extend(relativeTime)
dayjs.extend(customParseFormat)
dayjs.extend(utc)
dayjs.extend(timezone)   // after utc

dayjs.locale('en')

export default dayjs
```

---

_Generated June 2026 from iamkun/dayjs at 6609c5e. AI-generated documentation. The library is checked by sampling (three repositories so far); this guide was not individually reviewed. Verify against the project before relying on it. Unofficial; not affiliated with or reviewed by the project._
