DEV Community

John Au-Yeung
John Au-Yeung

Posted on

Handling Dates in JavaScript

Subscribe to my email list now at http://jauyeung.net/subscribe/

Follow me on Twitter at https://twitter.com/AuMayeung

Many more articles at https://medium.com/@hohanga

Handling date and time are also important in many JavaScript programs. This is why JavaScript has a built-in Date object to handle manipulating dates. Dates objects contain a number that represents the milliseconds since January 1970 in UTC (the Linux epoch time).

We can do a lot of things with the Date object to manipulate dates. However, it has many quirks and missing functionality. Therefore, third-party libraries are better with handling dates than using the built-in Date object in many cases. Moment.js is one of the more popular ones, so it’s naturally it is the first choice when we need to manipulate dates in JavaScript.

Built in Date Object

To work with dates in JavaScript, we have to create a new Date object. The constructor for the date object takes zero or more arguments. When there are no arguments passed in, then Date object created will have the current date and time in your local time zone, as of the time of instantiation.

The parameters it can accept include a date string, another date object, or the (years, month index, day, hour, minutes, seconds, and milliseconds) together. We can pass in a date string as follows to the date constructor:

new Date('2019-01-01');

If we log the result, we get ‘Mon Dec 31 2018 16:00:00 GMT-0800 (Pacific Standard Time)’ since the date is stored in UTC and the browser is running on a computer in the Pacific Time Zone, which is 8 hours behind UTC at January 1, 2019 is when Pacific Standard Time.

As we can see, passing a date string to the Date constructor is confusing. Different browsers will parse date strings differently. Likewise, the Date.parse method also shouldn’t be used to parse date strings. We can see that date-only strings like the one we passed in are treated as UTC and not local time.

If we want to pass in a Date object to the constructor we can write:

new Date(new Date());

We get something like ‘Sun Oct 20 2019 10:57:58 GMT-0700 (Pacific Daylight Time)’ when we log the result. This is shown in your local time.

We can pass in the year, month index, day, hour, minutes, seconds, and milliseconds into the constructor. Only year and month are required. So we can write something like:

new Date(2019,0,1,0,0,0,0)

This will return ‘Tue Jan 01 2019 00:00:00 GMT-0800 (Pacific Standard Time)’ if we log it. Note that we have 0 in the second argument of the constructor. The second argument is the month index, which is 0 for January, 1 for February, and so on. So December would be 11. The rest of the arguments are what we expect. The first is the year, the third is the day, the fourth is hours, the fifth is minutes, 6th is seconds, and the last one is milliseconds.

We can convert a Date object to the UNIX timestamp, which is the number of milliseconds since January 1, 1970 UTC with the unary + operator, so if we write:

+new Date(2019,0,1,0,0,0,0)

We get 1546329600000 when we log the output because it coerces the date to a number.

Another way to get the timestamp is by using the .getTime() method.

To alter the individual components of a Date object like setting the hours or day or getting components of a Date like the day of the week or day of the month, there are methods to do that in a Date object.

Methods in the Date Object

There are methods in the Date object to get and set parts of dates, and convert time to UTC, or set time zone offset. Some important Date object methods include the following:

Date.now()

Returns the current time in the form of a UNIX timestamp with leap seconds ignored. This method is static.

Date.UTC()

Returns the current time in the form of a UNIX timestamp with leap seconds ignored. This method is static. It accepts the same arguments as the longest list of arguments for the Date constructor which is year, month index, day, hour, minutes, seconds, and milliseconds, but only year and month are required. We can use it as in the following code:

Date.UTC(2019,0,1,1,0,0,0)

Which we return something like 1546304400000.

Getter Functions

Date.getDate()

Returns the day of the month according to local time. For example, if we have:

const date = new Date(2019,0,1,0,0,0,0);  
console.log(date.getDate());

We would get 1 since we specified it as the day of the month in the constructor’s arguments.

Date.getDay()

Returns the day of the week (0–6) for the specified date according to local time, where 0 represents Sunday and 6 represents Saturday and 1 to 5 represents the days in between. For example, we can write:

const date = new Date(2019,0,1,0,0,0,0);  
console.log(date.getDay());

Then we get 2, which is Tuesday.

Date.getFullYear()

Returns the 4 digit year of the specified date according to local time. For example, we can write:

const date = new Date(2019,0,1,0,0,0,0);  
console.log(date.getFullYear());

Then we get 2019, which is the 4 digit year of date.

Date.getHours()

Return the hour (0–23) of the specified date according to local time. For example, we can write:

const date = new Date(2019,0,1,0,0,0,0);  
console.log(date.getHours());

Then we get 0 which is what we specified in the hours argument in the constructor.

Date. getMilliseconds()

Returns the milliseconds of the specified date from 0 to 999 according to local time. For example, we can write:

const date = new Date(2019, 0, 1, 0, 0, 0, 0);  
console.log(date.getMilliseconds());

This gets the milliseconds specified in the date object, which should return 0 as we specified in the constructor.

Date.getMinutes()

Returns the minute (0–59) of the specified date in local time. For example, we can write:

const date = new Date(2019, 0, 1, 0, 0, 0, 0);  
console.log(date.getMinutes());

Then we get 0 minutes as we specified in the constructor.

Date.getMonth()

Returns the month (From 0 for January to 11 for December) of the specified date according to local time. For example, we can write:

const date = new Date(2019, 0, 1, 0, 0, 0, 0);  
console.log(date.getMonth());

Then we get month 0 for January as we specified in the constructor.

Date.getSeconds()

Returns the seconds (0–59) in the specified date in local time. For example, we can write:

const date = new Date(2019, 0, 1, 0, 0, 0, 0);  
console.log(date.getSeconds());

Then we get 0 seconds as we specified in the constructor.

Date.getTime()

Returns the UNIX timestamp for the specified date, which is the number of milliseconds since January 1, 1970 00:00:00 UTC. For prior times, it will be negative. For example, we can write:

const date = new Date(2019, 0, 1, 0, 0, 0, 0);  
console.log(date.getTime());

Then we get 1546329600000 returned from the getTime() function. A shorthand for this is to use the unary + operator, like in the following code:

const date = new Date(2019, 0, 1, 0, 0, 0, 0);  
console.log(+date);

If we run the code above, we get the same result logged.

Date.getTimezoneOffset()

Return time zone offset in minutes for the current location set on your host device. For example, if we write:

const date = new Date(2019, 0, 1, 0, 0, 0, 0);  
console.log(date.getTimezoneOffset());

Then we get 480 if your host device is set to the Pacific Time Zone, since on January 1, 2019, the Pacific Time Zone is 8 hours behind UTC, so we get that the time zone offset is 480 minutes, which is 8 hours.

Date.getUTCDate()

Returns the day of the month, from 1 to 31, in the specified date according to UTC. For example, if we write:

const date = new Date(2019, 0, 1, 0, 0, 0, 0);  
console.log(date.getUTCDate());

We get 1 since we specified January 1, 2019 as the date.

Date.getUTCDay()

Return the day of the week from 0 to 6 according to the specified date in UTC. For example, if we write:

const date = new Date(2019, 0, 1, 0, 0, 0, 0);  
console.log(date.getUTCDay());

Then we get 2 because January 1, 2019 is Tuesday.

Date.getUTCFullYear()

Return the 4 digit year in the specified date according to UTC. For example, if we write:

const date = new Date(2019, 0, 1, 0, 0, 0, 0);  
console.log(date.getUTCFullYear());

We get 2019 since this is what we specified in the date constructor.

Date.getUTCHours()

Return the hours from 0 to 23 in the specified date according to UTC. For example, if we write:

const date = new Date(2019, 0, 1, 0, 0, 0, 0);  
console.log(date.getUTCHours());

If the locale setting is set to the Pacific Time Zone, we get 8 since we specified that the hour is 0 in local time which is the same as 8 in UTC on January 1, 2019.

Date.getUTCMilliseconds()

Returns the milliseconds of the specified date from 0 to 999 according to UTC. For example, we can write:

const date = new Date(2019, 0, 1, 0, 0, 0, 0);  
console.log(date.getUTCMilliseconds());

This gets the milliseconds specified in the date object, which should return 0 as we specified in the constructor.

Date.getUTCMonth()

Return the month from 0 for January to 11 for December in the specified time according to UTC. For example, if we write:

const date = new Date(2019, 0, 1, 0, 0, 0, 0);  
console.log(date.getUTCMonth());

This gets the month specified in the date object, which should return 0 like we specified in the constructor.

Date.getUTCSeconds()

Returns the seconds (0–59) in the specified date in UTC. For example, we can write:

const date = new Date(2019, 0, 1, 0, 0, 0, 0);  
console.log(date.getUTCSeconds());

Then we get 0 seconds as we specified in the constructor.

Date.getYear()

Returns the year, which is usually 2 to 3 digits in the specified date according to the local time zone.

const date = new Date(2019, 0, 1, 0, 0, 0, 0);  
console.log(date.getUTCSeconds());

Then we get 119 for 2019.

If we instead have:

const date = new Date(1900, 0, 1, 0, 0, 0, 0);  
console.log(date.getYear());

We get 0 for 1900. And if we have:

const date = new Date(2000, 0, 1, 0, 0, 0, 0);  
console.log(date.getYear());

Then we get 100 for 2000. So 1900 is year 0 according to the getYear() method. It’s much better to use the getFullYear() method instead of getting the correct year from a Date object.

Setter Functions

There are also corresponding setter functions for each of the getter functions we mentioned above. We have the following setter functions for the Date object:

Date.setDate()

Sets the day of the month according to local time. For example, if we have:

const date = new Date(2019,0,1,0,0,0,0);  
date.setDate(2)  
console.log(date);

We would get ‘Wed Jan 02 2019 00:00:00 GMT-0800 (Pacific Standard Time)’ when the host device is set to the Pacific Time Zone since we specified 2 in the setDate function.

Date.setFullYear()

Sets the 4 digit year of the specified date according to local time. For example, we can write:

const date = new Date(2019,0,1,0,0,0,0);  
date.setFullYear(2020)  
console.log(date.getFullYear());

Then we get 2020, which is the 4 digit year of date.

Date.setHours()

Sets the hour (0–23) of the specified date according to local time. For example, we can write:

const date = new Date(2019,0,1,0,0,0,0);  
date.setHours(3)  
console.log(date.getHours());

Then we get 3 when we call getHours which is what we specified in the hours argument in the setHours function.

Date. setMilliseconds()

Sets the milliseconds of the specified date from 0 to 999 according to local time. For example, we can write:

const date = new Date(2019,0,1,0,0,0,0);  
date.setMilliseconds(3)  
console.log(date.getMilliseconds());

This sets the milliseconds specified in the date object, which should return 3 as we specified in the setMilliseconds function when we call the getMilliseconds function.

Date.setMinutes()

Sets the minute (0–59) of the specified date in local time. For example, we can write:

const date = new Date(2019, 0, 1, 0, 0, 0, 0);  
date.setMinutes(20)  
console.log(date.getMinutes());

Then we get 20 minutes returned from getMinutes() like we specified in the setMinutes function.

Date.setMonth()

Sets the month (From 0 for January to 11 for December) of the specified date according to local time. For example, we can write:

const date = new Date(2019, 0, 1, 0, 0, 0, 0);  
date.setMonth(3)  
console.log(date.getMonth());

Then we get month 3 returned from getMonth() after we set it by setMonth()

Date.setSeconds()

Sets the seconds (0–59) in the specified date in local time. For example, we can write:

const date = new Date(2019, 0, 1, 0, 0, 0, 0);  
date.setSeconds(10);  
console.log(date.getSeconds());

Then we get 10 seconds from getSeconds() like we specified in the setSeconds function.

Date.setTime()

Sets the UNIX timestamp for the specified date, which is the number of milliseconds since January 1, 1970 00:00:00 UTC. For prior times, it will be negative. For example, we can write:

const date = new Date(2019, 0, 1, 0, 0, 0, 0);  
date.setTime(100)  
console.log(date.getTime());

Then we get 100 returned from the getTime() function since we set it to 100 with setTime .

Date.setUTCDate()

Sets the day of the month, from 1 to 31, in the specified date according to UTC. For example, if we write:

const date = new Date(2019, 0, 1, 0, 0, 0, 0);  
date.setUTCDate(2)  
console.log(date.getUTCDate(2));

We get 2 since we specified 2 in setUTCDate

Date.setUTCFullYear()

Sets the 4 digit year in the specified date according to UTC. For example, if we write:

const date = new Date(2019, 0, 1, 0, 0, 0, 0);  
date.setUTCFullYear(2020)  
console.log(date.getUTCFullYear());

We get 2020 with getUTCFullYear() since this is what we specified in the date setUTCFullYear() function.

Date.setUTCHours()

Sets the hours from 0 to 23 in the specified date according to UTC. For example, if we write:

const date = new Date(2019, 0, 1, 0, 0, 0, 0);  
date.setUTCHours(2)  
console.log(date.getUTCHours());

We get 2 with getUTCHours() since we specified it when we call setUTCHours().

Date.setUTCMilliseconds()

Sets the milliseconds of the specified date from 0 to 999 according to UTC. For example, we can write:

const date = new Date(2019, 0, 1, 0, 0, 0, 0);  
date.setUTCMilliseconds(10)  
console.log(date.getUTCMilliseconds());

This gets the milliseconds with getUTCMilliseconds(), which should return 10 as we specified in the setUTCMilliseconds().

Date.setUTCMonth()

Return the month from 0 for January to 11 for December in the specified time according to UTC. For example, if we write:

const date = new Date(2019, 0, 1, 0, 0, 0, 0);  
date.setUTCMonth(3);  
console.log(date.getUTCMonth());

This gets the month specified in the date object, which should return 3 from getUTCMonth() like we specified in the setUTCMonth() call.

Date.setUTCSeconds()

Sets the seconds (0–59) in the specified date in UTC. For example, we can write:

const date = new Date(2019, 0, 1, 0, 0, 0, 0);  
date.setUTCSeconds(10);  
console.log(date.getUTCSeconds());

Then we get 10 seconds when we called getUTCSeconds() since we specified in 10 when we called setUTCSeconds().

The setYear() method set the ye. It’s much better to use the setFullYear() method instead for getting the correct year from a Date object.

The Date object has a few limitations. For example, it doesn’t support time zones. This creates problems when we need time zones data in our dates. JavaScript dates only supports the local time zone, UTC, or time zone offsets relative to UTC. Only some of the conversions between these time zones are allowed when manipulating date objects. For example, when we convert Date objects to a date string, we can only choose between local time and UTC. The JavaScript Date object stores dates in UTC internally.

Moment.js

Manipulating time and date in JavaScript is painful because of the limitations that we discussed above. Even with the functions available with Date objects, there are plenty of chances for bugs and errors. Also, there are no functions for formatting times and dates which is a big problem. To solve this, we use moment.js. This is the best library available for dealing with time.

The native JavaScript Date objects have issues with time zones with YYYY-MM-DD dates being parsed into UTC time as opposed to local time. This creates bugs for developers who aren’t aware of this problem. See https://stackoverflow.com/questions/29174810/javascript-date-timezone-issue

Also there are differences in support for parts of Dates in different browsers. (See https://stackoverflow.com/questions/11253351/javascript-date-object-issue-in-safari-and-ie)

It is also hard to add and subtract timestamps with the built-in Date functions. There is no way to do this without writing a lot of code and doing a lot of checks. Also, there is no way to compare 2 times.

Formatting dates is also not available without writing your own code for using third party libraries.

Moment.js solves all of these issues by providing built-in functions to do all these common operations. It provides functions for parsing and formatting dates.

The moment constructor is where you can pass in a date string, and a moment object will be created. For example, you can pass in:

moment('2019-08-04')

You will get back a moment which you can compare with other moment objects, and add or subtract by different time spans.

If you do not pass in anything to the moment constructor, you get the current date and time.

It also takes a second argument. If you want to make sure a date is parsed as a YYYY-MM-DD date, then write moment(‘2019–08–04’, 'YYYY-MM-DD'). If you don’t know the format of your date or time, then you can pass in an array of possible formats and Moment will pick the right one:

moment('2019–08–04', ['YYYY-MM-DD', 'DD-MM-YYYY']);

After you create a Moment object, then you can do many things like formatting dates:

const a = moment('2019–08–04', 'YYYY-MM-DD').format('MMMM Do YYYY, h:mm:ss a');  
console.log(a);// August 4th 2019, 12:00:00 am

const b = moment('2019–08–04', 'YYYY-MM-DD').format('dddd');  
console.log(b);// Sunday

const c = moment('2019–08–04', 'YYYY-MM-DD').format("MMM Do YY");  
console.log(c);// Aug 4th 19

const d = moment('2019–08–04', 'YYYY-MM-DD').format('YYYY [escaped] YYYY');      
console.log(d);// 2019 escaped 2019

const e = moment('2019–08–04', 'YYYY-MM-DD').format();  
console.log(e);// 2019-08-04T00:00:00-07:00

From the above examples, we see that we can format dates in pretty much any way we want.

We can also tell what time span a date is relative to another date by writing:

const augDate = moment('2019–08–04', 'YYYY-MM-DD');  
const sepDate = moment('2019–09–04', 'YYYY-MM-DD');  
console.log(augDate.from(sepDate)); // a month ago

We can also add or subtract Moment dates:

const augDate = moment('2019–08–04', 'YYYY-MM-DD');  
const sepDate = moment('2019–09–04', 'YYYY-MM-DD');  
console.log(augDate.add(10, 'days').calendar()); // 08/14/2019  
console.log(augDate.subtract(10, 'days').calendar()); // 07/25/2019

It is easy to compare 2 dates:

moment('2010-01-01').isSame('2010-01-01', 'month'); // true  
moment('2010-01-01').isSame('2010-05-01', 'day');   // false, different month  
moment('2008-01-01').isSame('2011-01-01', 'month'); // false, different year

You can also check if a date has Daylight Saving Time in effect or not:

const augDate = moment('2019–08–04', 'YYYY-MM-DD');  
const decDate = moment('2019–12–04', 'YYYY-MM-DD');  
console.log(augDate.isDST()) // true  
console.log(decDate.isDST()) // false

And you can convert back to JavaScript date any time by calling the toDate() function on a Moment object.

As we can see, JavaScript’s Date object has limited capabilities when it comes to manipulating dates. It also doesn’t parse dates very well and has no ability for formatting dates easily. This is why we need to use libraries like Moment.js to fill in the gaps so we can create bug-free code that manipulates dates much more easily.

Top comments (8)

Collapse
 
patarapolw profile image
Pacharapol Withayasakpunt
  1. What is the correct way to write 2020-01-01 1:00, so that Date constructor / moment doesn't complain (without directly specifying Date format)?
  2. moment.js is large and mutable. One mighy consider alternatives, such as Luxon, date-fns or dayjs.
Collapse
 
aumayeung profile image
John Au-Yeung
  1. This is the closest thing I can find to format dates in the format you ask for gist.github.com/noromanba/6737784

  2. I think date-fns is also good.

Collapse
 
adam_cyclones profile image
Adam Crockett 🌀

Open your console and type Intl you might find some very useful date formatting power in this API as well as a bunch of other good stuff.

Collapse
 
aumayeung profile image
John Au-Yeung

There's actually a lot of features for internationalization un JavaScript, like sorting strings in a locale-sensitive manner, formatting numbers, plurals, lists, and showing relative time.

Dates are just the beginning.

Collapse
 
adam_cyclones profile image
Adam Crockett 🌀

I like the currency section of this API, fantasticly under utilized though 😅

Thread Thread
 
aumayeung profile image
John Au-Yeung

Yea. I only discovered it on MDN when I'm writing about it.

Collapse
 
osde8info profile image
Clive Da

you might also like to have a look at the JS date and time formatting functions

new Date().toLocaleDateString("en-GB", options);
new Date().toLocaleTimeString("en-GB")

Collapse
 
aumayeung profile image
John Au-Yeung

toLocaleDateString actually has lots of options to format dates.

It's also sensitive to locale, which is handy for formatting dates in any format in the world almost.