Date Manipulation in JavaScript - A Complete Guide

Feature image

In theory, handling dates as a developer is as simple as creating, storing, and, if necessary, manipulating dates. But as a Javascript developer, you would know this theory doesn’t hold long after you start working with dates for real. On top of different date-time formats, you have to consider timezone and locale differences.

For this reason, plenty of Javascript developers seek help from third-party libraries when they have to manage dates in an application. While these libraries reduce the task’s complexity, having a clear understanding of handling vanilla Javascript dates has its benefits.

This tutorial will introduce you to working with dates in vanilla Javascript, as well as useful third-party libraries to help you simplify more complex date-related tasks.


Javascript Date object

The Date object in Javascript is the main element when it comes to handling date and time. It records a single point in time as the milliseconds’ number elapsed since the 1st January 1970 00:00:00 (UTC). This date-time combination is known as the epoch time. As far as Javascript is concerned, it’s the beginning of time in the world.


Creating Dates

You can simply create a date using new Date() . You can pass parameters to the Date constructor to create a date of your choice. The given parameter can take different forms.

Pass a date string

You can pass a date string of an accepted format when creating a new Date object.

const date = new Date("2020-12-31");

Now, if we print the created date, it shows this.

Thu Dec 31 2020 01:00:00 GMT+0100 (Central European Standard Time)

In addition to the date we passed, the date object has more values, including a time and a timezone. Since we didn’t give a specific value for these parameters when creating the object, Javascript uses the local time and timezone of the code’s system.

If we want to pass the time or timezone with the parameter string, we can use a format like this.

YYYY-MM-DDTHH:mm:ss.sssZ

  • YYYY: year
  • MM: month (1 to 12)
  • DD: date (1 to 31)
  • HH: hour in 24-hour format (0 to 23)
  • mm: minutes (0 to 59)
  • ss: seconds (00 to 59)
  • sss: milliseconds (0 to 999)
  • T is used to separate the date and time in the string
  • If Z is present, the time is assumed to be in UTC. Otherwise, it assumes the local time.

However, if T and Z are not present, the string’s created date may give different results in different browsers. In that case, to always have the same timezone for the date, add +HH:mm or -HH:mm to the end.

let newDate = new Date("2021-09-23T23:45Z")
// Fri Sep 24 2021 01:45:00 GMT+0200 (Central European Summer Time)

newDate = new Date("2021-09-23T23:45");
// Thu Sep 23 2021 23:45:00 GMT+0200 (Central European Summer Time)

newDate = new Date("2021-09-23T23:45+05:30")
// Thu Sep 23 2021 20:15:00 GMT+0200 (Central European Summer Time)

You can get the same results using the Date.parse function instead of passing the date string to the Date constructor. Date.parse is indirectly being called inside the constructor whenever you pass a date string.

The format used in these strings is the ISO 8601 calendar extended format. You can refer to its details in the ECMAScript specification .

Pass date arguments

You can directly pass the date arguments to the Date constructor without using confusing date strings. The order and length of each year, month, etc., are exactly as in a date string.

let newDate = new Date(1998, 9, 30, 13, 40, 05);

When we inspect the created date’s outcome, we can notice one crucial difference in the final date.

Fri Oct 30 1998 13:40:05 GMT+0100 (Central European Standard Time)

What’s weird? When we created the date, we used 9 for the month, which we could assume to be September. However, when we print the result, the month is October instead. Why is that?

Javascript uses a zero-based index to identify each month in a year. This means, for Javascript, January is represented by 0 instead of 1. Similarly, October is represented by 9 instead of 10.

In this method of creating a date, we can’t pass an argument to indicate its time zone. So, it’s defaulted to the local time of the system. But we can use the Date.UTC function to convert the date to UTC before passing it to the Date constructor.

newDate = new Date(Date.UTC(1998, 09, 30, 13, 40, 05))
// Fri Oct 30 1998 14:40:05 GMT+0100 (Central European Standard Time)

Pass a timestamp

Remember that I mentioned Javascript stores the time elapsed since the epoch time in the Date object? We can pass this elapsed time value, called a timestamp, to indicate the date we are creating.

newDate = new Date(1223727718982)
// Sat Oct 11 2008 14:21:58 GMT+0200 (Central European Summer Time)

Create a Date object for the current date and time

If you want to create a Date object for the current date and time of the system, use the Date constructor without passing any argument.

let now = new Date()
// Sat Jan 09 2021 22:06:33 GMT+0100 (Central European Standard Time)

You can also use the Date.now() function for the same task.

now = Date.now()

Formatting dates

Javascript provides several built-in functions to format a date. However, these functions only convert the date to a format specific to each one.

Let’s see how each formatting function works.

let newDate = new Date("2021-01-09T14:56:23")

newDate.toString()
// "Sat Jan 09 2021 14:56:23 GMT+0100 (Central European Standard Time)"

newDate.toDateString()
// "Sat Jan 09 2021"

newDate.toLocaleDateString()
// "1/9/2021"

newDate.toLocaleTimeString()
// "2:56:23 PM"

newDate.toLocaleString()
// "1/9/2021, 2:56:23 PM"

newDate.toGMTString()
// "Sat, 09 Jan 2021 13:56:23 GMT"

newDate.toUTCString()
// "Sat, 09 Jan 2021 13:56:23 GMT"

newDate.toISOString()
// "2021-01-09T13:56:23.000Z"

newDate.toTimeString()
// "14:56:23 GMT+0100 (Central European Standard Time)"

newDate.getTime()
// 1610200583000

Internationalization API

ECMAScript Internationalization API allows the formatting of a date into a specific locale using the Intl object.

let newDate = new Date("2021-01-09T14:56:23")

//format according to the computer's default locale
Intl.DateTimeFormat().format(newDate)
// "1/9/2021"

//format according to a specific locale, e.g. de-DE (Germany)
Intl.DateTimeFormat("de-DE").format(newDate)
// "9.1.2021"

You can pass an options object to the DateTimeFormat function to display time values and customize the output.

let options = {
    year: "numeric",
    month: "long",
    weekday: "long",
    hour: "numeric",
    minute: "numeric",
}

Intl.DateTimeFormat("en-US", options).format(newDate)
// "January 2021 Saturday, 2:56 PM"

Custom date formats

If you want to format the date to any other format beyond what these functions provide, you’ll have to do so by accessing each part of the date separately and combining them.

Javascript provides the following functions to retrieve the year, month, date, and day from a Date object.

newDate.getFullYear() // 2021
newDate.getMonth()    // 0 (zero-based index)
newDate.getDate()     // 9
newDate.getDay()      // 6 (zero-based index starting from Sunday)
newDate.getHours()    // 14
newDate.getMinutes()  // 56
newDate.getUTCHours() // 9
newDate.getUTCDate()  // 9

Now, you can convert the date to a custom format using retrieved parts.


Updating dates

Javascript provides several methods to edit an already created date.

newDate = new Date("2021-01-08T22:45:23")

newDate.setYear(1998)
//Thu Jan 08 1998 22:45:23 GMT+0100 (Central European Standard Time)

newDate.setMonth(4)
//Fri May 08 1998 22:45:23 GMT+0200 (Central European Summer Time)

newDate.setDate(12)
//Tue May 12 1998 22:45:23 GMT+0200 (Central European Summer Time)

newDate.setHours(12)
newDate.setMinutes(21)
newDate.setUTCDate(26)
newDate.setUTCMinutes(56)

Comparing dates

If you want to know whether a specific date comes before another, you can use greater than and less than operators directly for comparison.

let first = new Date(2010, 3, 19)
let second = new Date(2010, 3, 24)

first > second      //false

However, if you want to check them for equality, neither == nor === operator works as intended.

first = new Date(2009, 12, 23)
second = new Date(2009, 12, 23)

console.log(first == second)  // false
console.log(first === second) // false

Instead, you have to retrieve the timestamp of each date and compare them for equality.

first.getTime() === second.getTime() // true

This is because Dates in JavaScript are objects, so each date has a different instance of the class, and the == or === operator are comparing the memory address instead of the actual values of the dates.


Javascript date manipulation libraries

We can find several Javascript date and time manipulation libraries as open-source projects or otherwise. Some of them, designed for all kinds of date-time manipulations, and some have a specific set of use cases. In this section, I’ll only talk about popular multi-purpose libraries.

Moment.js used to be the king of date manipulation libraries among Javascript developers. However, its developers recently announced that it’s focusing on maintaining the current codebase instead of adding new features. They recommend looking for an alternative solution for those who are working on new projects.

So, apart from Moment.js, what are the libraries we can use to make our life easier as developers?

Date-fns

Date-fns in an open-source library supporting date parsing and formatting, locales, and date arithmetics like addition and subtraction. It’s dubbed as Lodash for dates due to its versatility.

const datefns = require("date-fns");

let date = datefns.format(new Date(2017, 09, 12), "dd MMM yyyy");
date = datefns.format(new Date(2017, 09, 12), "dd.MM.yy");

As you can see, you can easily convert a date into your preferred format by passing a simple formatting string.

It also allows us to add and subtract dates easily.

let date = new Date(2019, 09, 22)

let newDate1 = datefns.addDays(date, 21)
let newDate2 = datefns.addYears(date, 2)
let newDate3 = datefns.subMonths(date, 3)

console.log(datefns.format(newDate1, 'dd/MM/yyyy')) // 12/11/2019
console.log(datefns.format(newDate2, 'dd/MM/yyyy')) // 22/10/2021
console.log(datefns.format(newDate3, 'dd/MM/yyyy')) // 22/07/2019

Luxon

Luxon is a date-time manipulation library created by one of the Moment.js developers to suit modern application requirements. Similar to Date-fns, Luxon offers data formatting and parsing functions. Also, it has native Intl support and is chainable.

let date = DateTime.local(2019, 08, 12)

console.log(date.toLocaleString(DateTime.DATETIME_FULL))
console.log(date.toLocaleString(DateTime.DATETIME_MED))

You can also measure the time interval between two dates.

let now = DateTime.local()
let later = DateTime.local(2021, 03, 12)

console.log(Interval.fromDateTimes(now, later).length('years'))

Summary

This tutorial discussed how to work with date and time in Javascript with and without external libraries. Working with dates is always painful in almost (if not all) programming languages. Fortunately for us, JS and its ecosystem of libraries do all the heavy work for us, allowing us to focus on building features.

Thanks for reading!