The Complete Guide to Day.js
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.
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
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';
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)"
}
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
}
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:00dayjs('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:00dayjs('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:00dayjs('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:00dayjs().startOf('day').toDate();
// Sun Nov 21 2021 00:00:00dayjs().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:59dayjs().endOf('day').toDate();
// Sun Nov 21 2021 23:59:59dayjs().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:00dayjs('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
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');
// 25dayjs('2021-01-25').format('MM');
// 01dayjs('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
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:
- firstDayOfWeek
- longDateFormat
- meridiem
- months
- monthsShort
- ordinal
- weekdays
- weekdaysMin
- 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)
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:00dayjs('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:00dayjs('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:00dayjs('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:00dayjs('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:00dayjs('01-02-2021').dayOfYear(-365).toDate();
// Wed Jan 01 2020 00:00:00dayjs('01-02-2021').dayOfYear(366).toDate();
// Sat Jan 01 2022 00:00:00dayjs('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.
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 PMdayjs.tz(dayjs(), 'Australia/Sydney').format('lll');
// Dec 21, 2021 2:45 AMdayjs.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.
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 daydayjs.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
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
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.
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().format
API 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 apreParsePostFormat
plugin, 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');// ١٧ مايو ٢٠٢٢ ١٤:١١
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.
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.
Until next time 👋