The Complete Guide to Day.js

Mirza Leka
18 min readDec 21, 2021

I’ve recently had an opportunity to replace a legacy code written in Moment.js with a newer date library. After looking up the alternatives, I quickly decided to go with Day.js. This guide will teach you why & how to use it.

Photo by Pixabay from Pexels

In case you are wondering why I’m not using the well-known date library — Moment.js, that’s because the team behind Moment.js recently announced that they are retiring the library. The library will no longer get updates and the team recommended a few alternatives, among which is Day.js.

I also want to point out that I’m using Day.js version 1.10.7, in case something changes in the future.

Why you should consider Day.js:

  • Modern date library with plenty of tools
  • Immutable objects
  • Tree-shaking (with plugins)
  • Minimalistic. Around 1/7 times lighter than Moment.js
  • Native Typescript, Node.js, and Deno support
  • Simple syntax and easy to learn
  • Millions of weekly downloads
Photo by Tima Miroshnichenko from Pexels

Setting up Day.js in your project

To install Day.js in your Node.js do the following:

npm init -y // initialize NPM project (if you haven't already)
npm i dayjs // install dayjs

And require it in your app:

const dayjs = require('dayjs');

The process is similar in the TypeScript project:

npm init -y
tsc init // initialize TS project (if you haven't already)
npm i dayjs

And import it into your app:

import * as dayjs from 'dayjs';

Optionally, you can edit the tsconfig.json file generated with tsc init command to set esModuleInterop to true,

// tsconfig.json
{
"compileOnSave": false,
"compilerOptions": {
"esModuleInterop": true,
...
},
...
}

which will allow you to import Day.js (and all of its plugins) like this,

import dayjs from 'dayjs';
Photo by Julien Bachelet from Pexels

Working with Day.js

When it comes to using, Day.js is similar to Moment.js. Not only the syntax, but it also allows you to chain methods, manipulate date, format, build, all in one line.

To run Day.js, simply type dayjs()and this will generate you a Day.js object with information about the current time.

dayjs();
//
{
"$D":21,
"$H":9,
"$L":"en",
"$M":11,
"$W":2,
"$d":"Tue Dec 21 2021 09:48:04 GMT+0100 (Central European Standard Time)",
"$m":48,
"$ms":913,
"$s":4,
"$u":"undefined",
"$x":{},
"$y":2021
}

Furthermore, you can pass in a date or string date in between brackets to create a Dayjs object from the value you passed:

dayjs(new Date());
//
{
...,
"$d": "Tue Dec 21 2021 09:50:49 GMT+0100 (Central European Standard Time)"
}
dayjs('10-10-2010');
//
{
...,
"$d": "Sun Oct 10 2010 00:00:00 GMT+0100 (Central European Standard Time)"
}
Photo by Pixabay from Pexels

Builders

Now let’s learn how to extract a Day.js object into a date. To do that, we attach a builder method to a Day.js object.

# toDate

dayjs().toDate();
// Tue Dec 21 2021 10:48:27 GMT+0100 (Central European Standard Time)

# toJSON

dayjs().toJSON();
// 2021-12-21T10:49:06.687Z

# toString

dayjs().toString();
// Tue, 21 Dec 2021 10:56:28 GMT

Other forms require plugins built into Day.js.

# toArray

import * as toArray from 'dayjs/plugin/toArray';
dayjs.extend(toArray);
dayjs().toArray();
// [2021, 11, 21, 10, 55, 22, 703]

# toObject

import * as toObject from 'dayjs/plugin/toObject';
dayjs.extend(toObject);
dayjs().toObject();
//
{
"date":21,
"hours":10,
"milliseconds":521,
"minutes":53,
"months":11,
"seconds":13,
"years":2021
}
Photo by Gala Wallpapers

Time Manipulation

Day.js can be used to manipulate time and date.

# add (Adds x amount of seconds, minutes, hours, days, etc, to date)

dayjs('1-1-2020').add(1, 'd').toDate();
// Thu Jan 02 2020 00:00:00
dayjs('1-1-2020').add(1, 'y').toDate();
// Fri Jan 01 2021 00:00:00

# subtract (Subtracts x amount of seconds, minutes, days, etc, from date)

dayjs('1-1-2020').subtract(1, 'd').toDate();
// Tue Dec 31 2019 00:00:00
dayjs('1-1-2020').subtract(1, 'y').toDate();
// Tue Jan 01 2019 00:00:00

The first parameter is always the numeric value and the second is the Day.js unit type (like ‘d’ for the day, ‘y’ for the year).
Units are case insensitive, and support plural and short forms.

You can flip the logic by using a negative numeric value. This will make add work like subtract and vice versa.

dayjs('1-1-2020').add(-100, 'y').toDate();
// Thu Jan 01 1920 00:00:00
dayjs('1-1-2020').subtract(-100, 'y').toDate();
// Mon Jan 01 2120 00:00:00

# startOf (Returns a cloned Day.js object and set it to the start of a unit of time)

dayjs().startOf('year').toDate();
// Fri Jan 01 2021 00:00:00
dayjs().startOf('day').toDate();
// Sun Nov 21 2021 00:00:00
dayjs().startOf('hour').toDate();
// Sun Nov 21 2021 15:00:00

# endOf (Returns a cloned Day.js object and set it to the end of a unit of time)

dayjs().endOf('year').toDate();
// Fri Dec 31 2021 23:59:59
dayjs().endOf('day').toDate();
// Sun Nov 21 2021 23:59:59
dayjs().endOf('hour').toDate();
// Sun Nov 21 2021 15:59:59

# manipulate (Allows you to change any part of the date by chaining unit type to the Day.js object)

dayjs('1-1-2020').year(2021).toDate();
// Fri Jan 01 2021 00:00:00
dayjs('1-1-2020').month(2).toDate();
// Sun Mar 01 2020 00:00:00 (months start from 0 in JavaScript)
dayjs('1-1-2020').date(31).hour(23).minutes(59).seconds(59)
.toDate();
// Fri Jan 31 2020 23:59:59
Photo by Towfiqu barbhuiya from Pexels

Formatting

Day.js can format time in a number of ways using previously mentioned unit types.

# Format

Format method takes format template as a parameter and returns a string in oppose to Day.js object. This means we are not going to attach a builder at the end.

dayjs('2021-01-25').format('DD');
// 25
dayjs('2021-01-25').format('MM');
// 01
dayjs('2021-01-25').format('YYYY');
// 2021
dayjs('2021-01-25').format('DD/MM/YYYY');
// '25/11/2021'
dayjs('2021-01-25').format('YYYY.DD, [random string] MM');
// '2021.25, random string 01'
dayjs('2021-01-25').format('YYYY-MM-DDTHH:mm:ss');
// '2021-01-25T00:00:00'

The trick here is if you write a unit type as a single letter, you will get the shortest abbreviation version. You can extend this by adding more letters (up to four). List of available formats.

dayjs('2021-01-25').format('D | MMM | YY');
// '25 | Jan | 21'
dayjs('2021-01-25').format('ddd | MMM | YYYY');
// 'Mon | Jan | 2021'
dayjs('2021-01-25').format('dddd, D : MMMM | YYYY');
// 'Monday, 25 : January | 2021'

# Localized Formats

Localized Formats serve as a wrapper for commonly used date formats. Because preferred formatting differs based on locale, there are a few localized format tokens that can be used based on its locale.

You also need to import a plugin to make use of these.

import * as localizedFormat from 'dayjs/plugin/localizedFormat';
dayjs.extend(localizedFormat);
dayjs('01-02-2021').format('L');
// '01/02/2021'
dayjs('01-02-2021').format('LL');
// 'January 2, 2021'
dayjs('01-02-2021').format('LLL');
// 'January 2, 2021 12:00 AM'
dayjs('01-02-2021').format('LLLL');
// 'Saturday, January 2, 2021 12:00 AM'

This type of formatting can be used for time formats as well.

dayjs('01-02-2021 23:59:59').format('LT');
// '11:59 PM'
dayjs('01-02-2021 23:59:59').format('LTS');
// '11:59:59 PM'

You can find a full list of formats here.

# Advanced Format

Advanced Format extends dayjs().format API to supply more format options.

Current Quarter

dayjs().format('Q') // 4

Current Week

dayjs().format('W'); // 51

Day of Month with ordinal

dayjs().format('Do'); // 21st

Current Hour

dayjs().format('k'); // 10

Local Time Zone (requires Time Zone plugin)

dayjs().format('z'); // GMT +1
dayjs().format('zzzz'); // Central European Standard Time GMT+1

More on advanced formats.

# Custom Parse Format

Custom Parse Format extends dayjs() the constructor to support custom formats of input strings. Basically, it allows us to pass the date format and locale into the Day.js object.

import * as 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');
// Returns an instance containing date
'
Fri May 02 1969 19:02:03 GMT+0100'
dayjs('05/02/69 1:02:03 PM -05:00', 'MM/DD/YY H:mm:ss A Z', 'es');
// Returns an instance containing date and 'es' locale
'
Fri May 02 1969 19:02:03 GMT+0100'

# UTC Format

This returns a Day.js object with a flag to use UTC time.
It requires a UTC plugin.

import * as utc from 'dayjs/plugin/utc';
dayjs.extend(utc);
dayjs('1-1-2021').format();
// '2021-01-01T00:00:00+01:00'
dayjs('1-1-2021').utc().format();
// '2020-12-31T23:00:00Z'

If you want to parse or display a date-time in UTC, you can use dayjs.utc() instead of dayjs().

dayjs.utc('1-1-2021').format();
// 2020-12-31T23:00:00Z

Both options return the Day.js object, so you can chain methods to it.

dayjs.utc('1-1-2021 23:59:45').seconds(); // 45
dayjs.utc('1-1-2021 23:59:45').minutes(); // 59
dayjs.utc('1-1-2021 23:59:45').date(); // 1
dayjs.utc('1-1-2021 23:59:45').year(); 2021
dayjs.utc('1-1-2021 23:59:45').add(10, 'y').toDate();
// Wed Jan 01 2031 23:59:45

Going back to the previous implementationdayjs().utc() you can pass a boolean insideutc() to keep local time. Passing true will change the time zone without changing the current time.

dayjs('2016-05-03 22:15:01').utc(true).format();
// '2016-05-03T22:15:01Z'
dayjs('2016-05-03 22:15:01').utc().format();
// '2016-05-03T20:15:01Z'

Local Date

dayjs().local().toDate(); 
// Tue Dec 21 2021 09:56:13 GMT+0100 (Central European Standard Time)

UTC Offset

dayjs().utcOffset(); // 60

isUTC (Verify if the given date is UTC date)

dayjs().isUTC(); // false
dayjs.utc().isUTC(); // true
Photo by Monstera from Pexels

Locales

Next up, you can format the date based on the locale. For example:

import 'dayjs/locale/en-gb';
import 'dayjs/locale/bs';
import * as localizedFormat from 'dayjs/plugin/localizedFormat';
dayjs.extend(localizedFormat);dayjs().locale('en-us').format('ll'); // Dec 21, 2021
dayjs().locale('en-gb').format('ll'); // 21 Dec 2021
dayjs().locale('bs').format('ll'); // 21. dec. 2021

Thing is, each locale you plan to use must be imported manually, except for ‘en-us’ that is the default.
If you are importing a locale that doesn’t exist you’ll get an error. You can see the list of supported locales here.

You can also set locale globally and it will apply for all latter date formats.

import 'dayjs/locale/es';
import * as localizedFormat from 'dayjs/plugin/localizedFormat';
dayjs.extend(localizedFormat);dayjs.locale('es');
dayjs().format('ll'); // 21 de dic. de 2021

You can get the current global locale, by calling the locale method and without passing any parameters.

dayjs.locale(); // es

# Locale Data

Locale Data allows us to extract more information about the date based on locale. Basically calling dayjs().localeData()returns an object with useful information, like:

  1. firstDayOfWeek
  2. longDateFormat
  3. meridiem
  4. months
  5. monthsShort
  6. ordinal
  7. weekdays
  8. weekdaysMin
  9. weekdaysShort
import * as localeData from 'dayjs/plugin/localeData';
import 'dayjs/locale/bs';
dayjs.extend(localeData);dayjs().locale('en-us').localeData().weekdays();
// ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'];
dayjs().locale('bs').localeData().weekdays();
// ['nedjelja', 'ponedjeljak', 'utorak', 'srijeda', 'četvrtak', 'petak', 'subota'];

# Update Locale

If you are not satisfied with your locale format, Day.js allows you to update it yourself.

import * as updateLocale from 'dayjs/plugin/updateLocale';
import * as localizedFormat from 'dayjs/plugin/localizedFormat';
dayjs.extend(updateLocale);
dayjs.extend(localizedFormat);
dayjs().locale('es').format('ll'); // 21 de dic. de 2021 (regular)
const formats = {
'll': '[de] YYYY D [de] MMM.'
};
dayjs.updateLocale('es', { formats });

dayjs().locale('es').format('ll'); // de 2021 21 de dic. (updated)
Photo by Tima Miroshnichenko from Pexels

Picking the right Date

# Day of the Week

One interesting form is day() which returns the day of the week in number format.

dayjs('01-02-2021').day(); 
// 6 (because 2nd January 2021 was Saturday)

It can also accept numbers from 0 (Sunday) to 6 (Saturday). If the range is exceeded, it will bubble up to other weeks.

dayjs('01-02-2021').day(0).toDate(); 
// Sun Dec 27 2020 00:00:00 (first date of the week)
dayjs('01-02-2021').day(4).toDate();
// Thu Dec 31 2020 00:00:00 (fifth date of the week)

Changing the weeks:

dayjs('01-02-2021').day(7).toDate();
// Sun Jan 03 2021 00:00:00 (week after)
dayjs('01-02-2021').day(-1).toDate();
// Sat Dec 26 2020 00:00:00 (week before)

# Date of the Month

You can also return the date based on the date of the month.

dayjs('01-02-2021').date(1).toDate();
// Fri Jan 01 2021 00:00:00
dayjs('01-02-2021').date(31).toDate();
// Sun Jan 31 2021 00:00:00

If you pass a number below 1, this will return the date from the previous months.

dayjs('01-02-2021').date(0).toDate();
// Thu Dec 31 2020 00:00:00
dayjs('01-02-2021').date(-100).toDate();
// Tue Sep 22 2020 00:00:00

Similarly, adding more days than the current month has will select the date from the future.

dayjs('01-02-2021').date(32).toDate();
// Mon Feb 01 2021 00:00:00
dayjs('01-02-2021').date(100).toDate();
// Sat Apr 10 2021 00:00:00

# Day of the Year

Returns the current day of the year.

import dayOfYear from 'dayjs/plugin/dayOfYear';
dayjs.extend(dayOfYear);
dayjs('01-02-2021').dayOfYear(); // 2 (2nd day of the year)
dayjs('05-31-2021').dayOfYear(); // 151
dayjs('12-31-2021').dayOfYear(); // 365

Also can accept numbers from 1 to 366.

dayjs('01-02-2021').dayOfYear(1).toDate(); 
// Fri Jan 01 2021 00:00:00 (first date of the year)
dayjs('01-02-2021').dayOfYear(2).toDate();
// Sat Jan 02 2021 00:00:00
dayjs('01-02-2021').dayOfYear(365).toDate();
// Fri Dec 31 2021 00:00:00

If the range is exceeded, it will add or decrease the date.

dayjs('01-02-2021').dayOfYear(0).toDate();
// Thu Dec 31 2020 00:00:00
dayjs('01-02-2021').dayOfYear(-365).toDate();
// Wed Jan 01 2020 00:00:00
dayjs('01-02-2021').dayOfYear(366).toDate();
// Sat Jan 01 2022 00:00:00
dayjs('01-02-2021').dayOfYear(731).toDate();
// Sun Jan 01 2023 00:00:00

# Week of the Year

Used to retrieve or set the week of the year.

import * as weekOfYear from'dayjs/plugin/weekOfYear';
dayjs.extend(weekOfYear);
dayjs('01-02-2021').week(); // 1 (first week of the year)

Adding or decreasing the count will return the date in the future or the past.

dayjs('01-02-2021').week(5).toDate();
// Sat Jan 30 2021 00:00:00 (fifth week of the year)
dayjs('01-02-2021').week(-5).toDate();
// Sat Nov 21 2020 00:00:00 (five weeks before)

# Quarter of the Year

Quite self-explanatory returns quarter or sets date based on a quarter of the year.

import * as quarterOfYear from 'dayjs/plugin/quarterOfYear';
dayjs.extend(quarterOfYear);
dayjs('01-02-2021').quarter(); // 1 (first quarter of the year)
dayjs('01-02-2021').quarter(1).toDate();
// Sat Jan 02 2021 00:00:00 (sets date to 1st quarter)
dayjs('01-02-2021').quarter(3).toDate();
// Fri Jul 02 2021 00:00:00 (sets date to third quarter)
dayjs('01-02-2021').quarter(0).toDate();
// Fri Oct 02 2020 00:00:00 (sets date to previous quarter)

# Display the Unit

Lastly, you can display parts of the date by attaching a unit type and not passing any parameters.

dayjs('01-02-2021').year(); // 2021
dayjs('01-02-2021').month(); // 0 (months are 0th index)
dayjs('01-02-2021').date(); // 2

The same applies to quarters, weeks, hours, minutes, or seconds.

Photo by Pixabay from Pexels

Time Zones

Day.js supports time zone via the Internationalization API in supported environments. By using the native API, no extra bytes of time zone data need to be included in the code bundle

To work with time zones, you need to import Time Zone and UTC plugins.

import * as timezone from 'dayjs/plugin/timezone';
import * as utc from 'dayjs/plugin/utc';
import * as localizedFormat from 'dayjs/plugin/localizedFormat';
dayjs.extend(utc);
dayjs.extend(timezone);
dayjs.extend(localizedFormat);

With this in place, we can now toggle dates based on time zone.
Example of the current time in my time zone, versus several others.

dayjs.tz(dayjs(), 'Europe/Sarajevo').format('lll');
// Dec 20, 2021 4:45 PM
dayjs.tz(dayjs(), 'Australia/Sydney').format('lll');
// Dec 21, 2021 2:45 AM
dayjs.tz(dayjs(), 'America/New_York').format('lll');
// Dec 20, 2021 10:45 AM

# guess (Guess user’s zone)

dayjs.tz.guess(); // Europe/Sarajevo

# setDefault (Set default time zone)

dayjs.tz.setDefault('America/New_York');

This one is a little buggy as it will still show the user’s time zone, despite what you set as a default. However, there is a workaround.
The same method can also be used for resetting the time zone.

# setDefault (Reset default time zone)

dayjs.tz.setDefault();

Be sure to check the docs to see what else is in store.

Photo by Erik Mclean from Pexels

Duration

Day.js also has duration objects. Where a Day.js object is defined as single points in time, durations are defined as a length of time.
Durations do not have a defined beginning and end date. They are contextless.

To create a duration, import a duration plugin and call dayjs.duration() with the length of time and optionally a unit type.

import * as duration from 'dayjs/plugin/duration';
dayjs.extend(duration);
dayjs.duration();
// returns a dayjs object with date
{
days: 0,
hours: 0,
milliseconds: 0,
minutes: 0,
months: 0,
seconds: 0,
years: 0
};
among other things like locale and miliseconds
dayjs.duration(100); // { ..., miliseconds: 100 }
dayjs.duration(1, 'd') // { ..., days: 1 }

Duration can be used to convert time length into different unit types.

dayjs.duration(60, 's'); // { ..., minutes: 1 }
dayjs.duration(86400, 's'); // { ..., days: 1 }
dayjs.duration(100, 'h'); // { ..., days: 4, hours: 4 }
dayjs.duration(500, 'h'); // { ..., days: 20, hours: 20 }
dayjs.duration(100, 'd'); // { ..., months: 3, days: 10 }
dayjs.duration(500, 'd'); // { ..., years: 1, months: 4, days: 15 }

# Humanize

Humanize is used to express Day.js Duration into a human-readable format.
It’s dependent on both Duration and Relative Time plugins.

import * as duration from 'dayjs/plugin/duration';
import * as relativeTime from 'dayjs/plugin/relativeTime;
dayjs.extend(duration);
dayjs.extend(relativeTime);
dayjs.duration(60, 's').humanize(); // a minute
dayjs.duration(24, 'h').humanize(); // a day
dayjs.duration(500, 'h').humanize(); // 21 days
dayjs.duration(100, 'd').humanize(); // 3 months

Humanize can also be used to describe past and future dates by passing true as a parameter to humanize() function.

dayjs.duration(100, 'd').humanize(true); // in 3 months
dayjs.duration(-100, 'd').humanize(true); // 3 months ago

# As… unit type

This is another way to convert durations into the desired format.

dayjs.duration(365, 'd').asMilliseconds(); // 31536000000
dayjs.duration(365, 'd').asSeconds(); // 31536000
dayjs.duration(365, 'd').asMinutes(); // 525600
dayjs.duration(365, 'd').asHours(); // 8760
dayjs.duration(365, 'd').asDays(); // 365
dayjs.duration(365, 'd').asMonths(); // 12.66
dayjs.duration(365, 'd').asYears(); // 1

Durations can be combined with almost everything previously mentioned, to manipulate and format the date, so be sure to check the docs for more.

# Relative Time

Relative Time adds .from .to .fromNow .toNow APIs to format date to relative time strings.

import * as relativeTime from 'dayjs/plugin/relativeTime;
dayjs.extend(relativeTime);

To

dayjs().to(dayjs('1920-21-12')); // 100 years ago
dayjs().to(dayjs('1920-21-12'), true); // 100 years

From

dayjs().from(dayjs('1920-21-12')); // in 100 years
dayjs().from(dayjs('1920-21-12'), true); // 100 years

To now

dayjs('1920-21-12').toNow(); // in 100 years
dayjs('1920-21-12').toNow(true); // 100 years

From now

dayjs('2120-21-12').fromNow(); // in 100 years
dayjs('2120-21-12').fromNow(true) // 100 years
Photo by Jennifer Field from Pexels

Validations

Day.js comes with a handful of functions to validate and compare the dates.

# isSame (Validates if two dates are the same)

dayjs('1-1-2021').isSame(dayjs('1-1-2021')); // true
dayjs('1-1-2020').isSame(dayjs('1-1-2021')); // false

# isBefore (Validates if the first date is before the second)

dayjs('1-1-2020').isBefore(dayjs('1-1-2021')); // true
dayjs('1-1-2021').isBefore(dayjs('1-1-2020')); // false

# isAfter (Validates if the first date is after the second)

dayjs('1-1-2020').isAfter(dayjs('1-1-2021')); // false
dayjs('1-1-2021').isAfter(dayjs('1-1-2020')); // true

# isToday (Validates if the date is today)

import * as isToday from 'dayjs/plugin/isToday';
dayjs.extend(isToday);
dayjs().isToday(); // true
dayjs().add(1, 'd').isToday(); // false

# isTomorrow (Validates if the date is tomorrow)

import * as isTomorrow from 'dayjs/plugin/isTomorrow';
dayjs.extend(isTomorrow);
dayjs().isTomorrow(); // false
dayjs().add(1, 'd').isTomorrow(); // true

# isYesterday (Validates if the date was yesterday)

import * as isYesterday from 'dayjs/plugin/isYesterday';
dayjs.extend(isYesterday);
dayjs().isYesterday(); // false
dayjs().subtract(1, 'd').isYesterday(); // true

# isBetween (Validates if picked date between two dates)

import * as isBetween from 'dayjs/plugin/isBetween';
dayjs.extend(isBetween);
dayjs('1-1-2020').isBetween('1-1-2010', '1-1-2030'); // true
dayjs('1-1-2000').isBetween('1-1-2010', '1-1-2030'); // false

# diff (Returns difference between two dates)

const date1 = dayjs('1-1-2019');
const date2 = dayjs('1-1-2020');
date2.diff(date1); // 31536000000

It defaults to milliseconds, but you can pass any unit type as a second argument:

date2.diff(date1, 'hour'); // 8760
date2.diff(date1, 'day'); // 365
date2.diff(date1, 'week'); // 52
date2.diff(date1, 'month'); // 12
date2.diff(date1, 'quarter'); // 4
date2.diff(date1, 'year'); // 1

# isLeapYear (Validates if the year is a leap year)

import * as isLeapYear from 'dayjs/plugin/isLeapYear';
dayjs.extend(isLeapYear);
dayjs('1-1-2020').isLeapYear(); // true
dayjs('1-1-2021').isLeapYear(); // false
Photo by Tima Miroshnichenko from Pexels

Immutable vs Mutable Dates

A mutable object can be changed after it’s created, and an immutable object can’t.
Interviewcake

Unlike in Moment.js, Day.js objects are immutable.

# Clone

You can create a clone of the Day.js object with the use of clone() whilst two objects remain separate.

const a = dayjs();
const b = a.clone();
a.toDate(); // Tue Dec 21 2021 10:48:27 GMT+0100 (Central European Standard Time)b.toDate(); // Tue Dec 21 2021 10:48:27 GMT+0100 (Central European Standard Time)

To prove that they are different, I’ll change one and then display both.

a.add(1, 'day').toDate(); // Wed Dec 22 2021 10:48:27 GMT+0100 (Central European Standard Time)b.toDate(); // Tue Dec 21 2021 10:48:27 GMT+0100 (Central European Standard Time)

Calling dayjs() on a Day.js object will clone it as well.

const a = dayjs();a.toDate(); // Tue Dec 21 2021 10:48:27 GMT+0100 (Central European Standard Time)a.add(1, 'day').toDate(); // Wed Dec 22 2021 10:48:27 GMT+0100 (Central European Standard Time)a.toDate(); // Tue Dec 21 2021 10:48:27 GMT+0100 (Central European Standard Time)

The change is not reflected.

# Bad Mutable

To make Day.js objects mutable, you can use the Bad Mutable plugin.
This is not recommended.

import * as badMutable from 'dayjs/plugin/badMutable';
dayjs.extend(badMutable);
const today = dayjs();today.add(1, 'day').toDate(); // Wed Dec 22 2021 10:48:27 GMT+0100 (Central European Standard Time)today.toDate(); // Wed Dec 22 2021 10:48:27 GMT+0100 (Central European Standard Time)

The change is shared across instances.

Photo by Nikola Nemeš from Pexels

Gregorian, Buddhist, Jalali Calendar, and Arabic Numerals

By default, Day.js works with the Gregorian calendar, but you can also make adjustments.

# Budhhist Era

Buddhist Era extends dayjs().formatAPI to supply Buddhist Era (B.E.) format options. By convention, the Buddhist Year starts with Wesak full-moon in the month of May. Therefore, before ‘Buddha Day’ on 26 May 2021, the year is B.E. 2564 (current Gregorian year + 543).

dayjs().format('BBBB'); // 2564
dayjs().format('BB'); // 64

Unfortunately, it doesn’t work if you use any of the standard formats like DD/MM/YYYY or Localized Format. You have to use the letter B for the year. However, nothing stops you from updating the date manually before the formatting.

const template = 'DD/MM/YYYY';
const buddhistEraTemplate = template.replace(/y/gi, 'B');
dayjs().format(buddhistEraTemplate);
// '21/12/2564'

# Jalali Calendar

The Jalali calendar is a solar calendar in use today in Iran and Afghanistan.
Day.js doesn’t support it out of the box, but there is a library Jalali Day that extends Day.js API and converts Gregorian to Jalali date.

npm install --save jalaliday

Unfortunately, the library doesn’t support TypeScript, so I’ll use Node.js in this chapter.

const jalaliday = require('jalaliday');
dayjs.extend(jalaliday);

Day.js will still default to the Gregorian calendar, so you need to set the Jalali calendar manually, either globally (so that all instances of Day.js to use Jalali calendar)

dayjs.calendar('jalali');

Or you can set it inline:

dayjs().calendar('jalali').format('DD MMMM YYYY'); // 30 Aazar 1400
dayjs().format('DD MMMM YYYY'); // 21 December 2021 (regular date)

If you include the Persian locale (fa), you can translate the data to its native language.

require('dayjs/locale/fa');dayjs('12-21-2021').calendar('jalali').locale('fa')
.format('DD YYYY MMMM')
// 30 آذر 2021

# Arabic Numerals

One thing you will often see in Arabic calendars (and Moment.js) is Arabic numerals. Day.js supports this well with the use of a plugin.

import * as dayjs from 'dayjs';
import 'dayjs/locale/ar'
import * as localizedFormat from 'dayjs/plugin/localizedFormat';

dayjs.extend(localizedFormat);

dayjs().locale('ar').format('LLL');
// 17 مايو 2022 14:11

But if you import and extend apreParsePostFormatplugin, the date format will update:

import * as dayjs from 'dayjs';
import 'dayjs/locale/ar'
import * as localizedFormat from 'dayjs/plugin/localizedFormat';
import * as preParsePostFormat from 'dayjs/plugin/preParsePostFormat';

dayjs.extend(localizedFormat);
dayjs.extend(preParsePostFormat);

dayjs().locale('ar').format('LLL');
// ١٧ مايو ٢٠٢٢ ١٤:١١
Photo by Monoar Rahman from Pexels

Caveats

After saying nothing but praises about Day.js up until this point, I think it’s time to reveal some frustrations I had with it and solutions for the same.

# Format Hours

You might have seen something like this in Moment.js:

const time = '23:59';
const format = 'HH:mm';
moment(time, format).toDate(); // Current date

Running the same command in Day.js would return you an invalid date:

dayjs(time, format).toDate(); // Invalid date

That’s because Day.js expects a customParseFormat plugin to tell it how to format the date. The issue is fixed if you do the following:

import * as customParseFormat from 'dayjs/plugin/customParseFormat';
dayjs.extend(customParseFormat);
dayjs(time, format).toDate(); // Current date

# Meridiem

Meridiem returns AM or PM variant of a locale you are using depending on the time of day you are at.

dayjs().locale('en-us').localeData().meridiem(); // AM or PM

The problem with Day.js is that it has many locales and very few of them have a meridiem. Around 10 in total.
This means if the locale is dynamic in your app and you type dayjs().localeData().meridiem(), in most cases you will get an error saying ‘meridiem is not a function.’

dayjs().locale('es').localeData().meridiem();// dayjs__WEBPACK_IMPORTED_MODULE_1__(...).locale(...).localeData(...).meridiem is not a function

To resolve this, you can make use of updateLocale and set a custom meridiem for each of your locales.

const meridiem = (hour?) => hour > 12 ? 'PM' : 'AM';
dayjs.updateLocale('es', { meridiem });
const currentHour = dayjs().hour();
dayjs().locale('es').localeData().meridiem(currentHour); // PM

# Importing Locales

Day.js gives you only one locale by default, an ‘en-us’ locale. As for others, it requires you to import each one by one. This can be tedious and leaves a lot of DRY code especially if you are working with many languages.

a) First way to solve this is to create a separate file, (e.g. dayjs-locales.ts) and import all of your modules there.

import 'dayjs/locale/en-gb';
import 'dayjs/locale/de';
import 'dayjs/locale/fr';
...

Then you import this file in whichever file you are using Day.js:

import './dayjs-locales';

b) Another way to do this is to make use of the Dynamic Expressions in Import JavaScript feature to import each module on form change (like a button click, dropdown event, etc.) or through a loop.

const language = 'en-gb';import(`dayjs/locale/${language}`)
.then((lang) => {
// do something
})
.catch((e) => {
// handle exception
});

After locales have been imported you can use them anywhere.

dayjs().locale(language).format('L');

# Plugins

Day.js has a lot of plugins that you can import, which is a good thing, as you do not need to import the whole library at once as is the case with Moment.js. However, coming from Moment.js you might find it surprising that a lot of the functionalities you’d expect to work don’t. Many functionalities require plugins. So you have to look through docs and GitHub issues until you find the missing plugin and import it.
It can be both hit and miss.

Photo by Claudio Mota from Pexels

Conclusion

Day.js is a minimalistic, easy-to-use, production-ready date library with a bright future. It has its own highs and lows. especially when it comes to locales and time zones, but most of its flaws can be avoided with clever engineering.

It’s open-source and contributions are welcome.

It’s been both a challenging and fun journey and I encourage everyone to give it a try.

If you like my work you can support me with a cup of coffee

Until next time 👋

--

--

Mirza Leka

Web Developer. DevOps Enthusiast. I share my experience with the rest of the world. Follow me on https://twitter.com/mirzaleka for news & updates #FreePalestine