Jesse A. Green / notebook

Day.js User Guide

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.

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ย 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.

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
  2. Why Day.js
  3. Installation
  4. Core Concepts
  5. Parsing โ€” Creating Day.js Objects
  6. Get and Set
  7. Manipulating Dates
  8. Displaying and Formatting
  9. Format Token Reference
  10. Querying and Comparing
  11. Plugins
  12. Internationalization (i18n)
  13. Common Tasks and Recipes
  14. Troubleshooting
  15. FAQ
  16. Quick Reference

1. Quick Start

Install the library and create your first date object.

npm install dayjs
import dayjs from 'dayjs'

// The current date and time
dayjs().format('YYYY-MM-DD HH:mm:ss')
'2019-03-06 15:25:00'
// 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')
'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ย 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 you extend at runtime, so your bundle only carries what you use.


3. Installation

npm

npm install dayjs --save

Yarn

yarn add dayjs

pnpm

pnpm add dayjs

CDN

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

Importing

ES Modules / bundlers

import dayjs from 'dayjs'

dayjs().format()

CommonJS (Node.js)

const dayjs = require('dayjs')

dayjs().format()

Browser global

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

<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

import dayjs from 'dayjs'

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

4. Core Concepts

Immutability

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

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'
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 plugin restores it. It is named "bad" on purpose: mutation is discouraged.

Chaining

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

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:

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:

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

dayjs()  // current date and time

ISO 8601 string

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

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):

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 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

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

Unix timestamp (milliseconds)

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

Unix timestamp (seconds)

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

dayjs.unix(1318781876)       // seconds โ†’ Day.js object
dayjs.unix(1318781876.721)   // fractional seconds are supported

Cloning an existing object

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

Null and undefined

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 for custom string formats, arraySupport for dayjs([2010, 1, 14]), objectSupport for dayjs({ year: 2010, month: 1 }), utc for UTC-mode parsing, and bigIntSupport for BigInt timestamps.


6. Get and Set

Getters

Call a unit method with no argument to read it:

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:

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:

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):

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)
// 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 plugin. The singular and short forms are always available.

Days in month

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

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:

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

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:

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 plugin and startOf('isoWeek').

Chaining manipulations

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:

dayjs('2019-01-25').format()
'2019-01-25T00:00:00+02:00'

Pass a template string of tokens:

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:

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

diff() โ€” difference between two dates

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:

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

Native conversions

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

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, calendar, localizedFormat, and 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

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:

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 <= comparison
isSameOrAfter isSameOrAfter >= comparison
isBetween isBetween Range check with inclusivity control
isToday / isTomorrow / isYesterday isToday etc. Relative-day checks
isLeapYear isLeapYear Leap-year check
isDayjs (static) core Type check
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.

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ย 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.

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).

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.

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().

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).

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.

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:

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.

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:

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:

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).

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.

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().

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:

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.

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().

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().

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.

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.

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).

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

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

isSameOrBefore

Adds isSameOrBefore() (a <= comparison).

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.

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.

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).

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.

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'.

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.

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().

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).

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.

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().

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"):

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

You can customize rounding and thresholds when extending:

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 plugin (which it requires): .tz(), .offsetName(), dayjs.tz(), dayjs.tz.guess(), and dayjs.tz.setDefault().

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).

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 }.

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.

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.

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).

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.

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.

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:

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):

import 'dayjs/locale/es'

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

Read the current global locale:

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:

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 plugin to override only certain fields (for example, to make the week start on Monday):

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

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

Get the start and end of today

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

Add business-friendly offsets

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

Difference in days between two dates

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

"Time ago" label

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

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

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

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

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:

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 โ€” 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ย 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

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