Back to top

Getting Started with Dates and Times in JavaScript

Published: Jan 2, 2024


Working with dates and times is an integral part of most web applications. Whether you need to display timestamps, schedule events, or calculate durations, JavaScript provides a built-in Date object to handle these date-related tasks programmatically.


In this section, we’ll cover the basics of using Date objects in JavaScript, including:


  • Creating Date instances
  • Accessing and setting date components
  • Comparing and manipulating Date objects
  • Converting dates to strings
  • Best practices

Creating New Dates


To create a new Date instance in JavaScript, you can use the Date() constructor:

const now = new Date();

This will create a Date object representing the current date and time.


You can also pass integer parameters to specify the date components:

const birthday = new Date(2023, 0, 19); // January 19th, 2023

Be aware that the month is 0-indexed, so 0 is January and 11 is December.


Pitfall Alert: Calling Date() without the new keyword will return a string rather than a Date object:

const badDate = Date(); // String instead of Date instance!

So make sure to always use new Date().


Accessing Date Components


Once you have a Date instance, you can use getter methods like .getFullYear(), .getMonth() and .getDate() to access specific date parts:

const now = new Date(); 

const year = now.getFullYear(); // 2023
const month = now.getMonth(); // 0 (January) 
const day = now.getDate(); // 25

There are also methods like .getHours(), .getMinutes() and .getSeconds() to access time components.


You can access the total timestamp with .getTime():

now.getTime(); // 1674687399013 (milliseconds since Jan 1 1970)

Formatting and Displaying Dates


After creating Date instances, we need to be able to properly format and display those dates to users.


JavaScript provides several built-in methods to format Date objects, as well as options for custom formatting.


Built-in Formatting Methods


The easiest way to format dates is using .toLocaleDateString():

const date = new Date(2023, 0, 19);

date.toLocaleDateString(); 
// "1/19/2023" (in US English locale)

This converts the Date to a string based on the user’s locale and machine settings.


Similarly, you can use .toLocaleTimeString() to format the time portion of a date:

date.toLocaleTimeString(); // "5:49:21 PM"

Other built-in formatting methods include:


  • .toString() - returns machine readable date/time string
  • .toUTCString() - converts to UTC string format
  • .toISOString() - formats according to ISO-8601 standard

For example:

date.toUTCString(); // "Thu, 19 Jan 2023 21:56:35 GMT"  

date.toISOString(); // "2023-01-20T02:56:35.182Z" 

Custom Formatting


If you need more customization than the built-in methods offer, you can create your own formatting functions:


function formatDate(date) {
const day = date.getDate();
const month = date.getMonth() + 1; 
const year = date.getFullYear();  
return `${month}/${day}/${year}`; // "1/19/2023"  
}

This allows formatting dates exactly how you need them for your application UI.


Date Manipulation and Calculations


Once you’ve created Date objects, you often need to manipulate them by adding/subtracting time or calculating differences between dates.


Adding and Subtracting Dates


We can manipulate Date instances using the setter methods like .setDate(), .setMonth() and .setFullYear().


For example, to increment a date by 1 day:

const date = new Date(2023, 0, 19); 

date.setDate(date.getDate() + 1);

console.log(date); // Fri Jan 20 2023 00:00:00

Other useful methods include:

  • .setHours()
  • .setMinutes()
  • .setSeconds()

We can use these to easily calculate future or past dates:

const oneWeekAgo = new Date();
oneWeekAgo.setDate(oneWeekAgo.getDate() - 7);

Subtracting dates also allows us to find durations between dates.


Calculating Date Differences


A simple way to calculate the difference between two dates is by subtracting their timestamps:

const date1 = new Date(); // now
const date2 = new Date(2023, 5, 17); // Jun 17, 2023
const diffTime = date2 - date1; // milliseconds between dates
const diffDays = diffTime / (1000 * 3600 * 24); 

This allows us to find differences in days, weeks, months etc.


We could even create reusable functions for common duration calculations:

function daysBetween(date1, date2) {
const timeDiff = Math.abs(date2 - date1);  
return Math.ceil(timeDiff / (1000 * 3600 * 24));  
}

const days = daysBetween(new Date('2023-01-19'), new Date('2023-01-25')); // 6 days

Advanced Date Handling and Libraries


JavaScript’s built-in Date object provides decent basic date handling functionality. But for more advanced use cases, dedicated date libraries like Moment.js and Luxon.js are extremely useful.


Overview of Moment.js


Moment.js is the most popular date handling library for JavaScript. It wraps the native Date object with an easier API and helpful features like:


  • Simplified date creation and manipulation
  • Powerful and customizable formatting
  • Timezone support
  • Locale awareness
  • Relative time capabilities
  • Duration calculations
  • Calendar time capabilities

For example, formatting with Moment looks cleaner:


const now = moment();
now.format("MMM Do YY"); // "Jan 25th 23"

And duration calculations are simpler:

const duration = moment.duration(2, 'days'); // 2 day duration
const newDate = moment().add(duration); // Add 2 days  

Overview of Luxon


Luxon is a newer alternative to Moment focused on immutability and partitioning date handling concerns:

import { DateTime } from 'luxon';

const dt = DateTime.local(); // Current date/time

dt.plus({ weeks: 1 }); // New date 1 week later

It also provides robust format and locale support.


Choosing a Library


So which library should you choose? Here are a few key considerations:


Familiarity - If coming from Moment, Luxon has a steeper learning curve. But its API may feel cleaner.


Bundle Size - Luxon is lighter weight. Moment’s localization data increases bundle size.


Immutability - A core Luxon principle that prevents bugs.


Both libraries provide excellent date handling capabilities - so evaluate them against your specific needs.


Best Practices and Troubleshooting


When working with dates in JavaScript, there are some best practices worth following to avoid common pitfalls and issues.


Avoiding Common Mistakes


Here are some tips for avoiding the most common date-related bugs:

  • Always create dates with new Date(), not just Date()
  • Be careful working across time zones
  • Stringify dates before storing in database
  • Don’t rely on browser locale settings for formatting
  • Use a library for complex date calculations

Following ISO-8601 date string standard can also prevent inconsistencies.


Debugging Date Issues


If you do run into strange date behavior, here are some debugging tips:

  • Check order of date parameters passed to Date constructor
  • Log raw timestamp values using .getTime()
  • Print dates with .toISOString() for standardized format
  • Confirm timezone is set properly in environment
  • Test code across various browser locales

Tools like console warnings and breakpoints can trace odd date outputs.


Cross-Browser Consistency


The JavaScript Date spec has good browser support, but inconsistencies do occur:

  • Some browsers handle Daylight Saving Time shifts differently
  • Support for newer Intl APIs varies across browsers
  • Older browsers may output different default formats

Feature detecting and abstracting browser variances is recommended. Testing your code locally across browser sandboxes can uncover these inconsistencies.


Handling Time Zones


Dealing with timezones is crucial for robust date handling in web apps used globally.


Understanding UTC


The key to managing timezones is understanding UTC (Coordinated Universal Time). UTC provides a standard reference point for different timezones:

New York: UTC-5
Berlin: UTC+1 
Tokyo: UTC+9

Think of UTC as the “baseline” timezone at 0 offset. All other timezones are expressed relative to UTC.


We can convert between UTC and local time using Date methods like:

  • .getTimezoneOffset() - returns offset in minutes from UTC
  • .toUTCString() - converts date to UTC string

Managing Timezone Differences


The main challenge with timezones is displaying the same absolute date/time across multiple timezones:

Event starts at Jan 25th 2023, 9:00 UTC 

In UTC: 9:00
In Tokyo (UTC+9): 18:00 // 9 hours later 
In NY (UTC-5): 4:00 // 9 hrs earlier

To handle these differences, best practice is to:

  • Store dates in UTC internally
  • Convert to local timezones for display only

This prevents inconsistent comparisons and calculations across timezones.


Handling Time Zones in Comparisons


Similarly, comparing Date objects across different time zones can cause issues:


const eventStart = new Date('Jan 25 2023 09:00 UTC');
const tokyoTime = convertToTimeZone(eventStart, 'Asia/Tokyo'); 
tokyoTime > eventStart; // False! Comparison fails

The key is to normalize dates to same timezone before comparing:

function compareDates(date1, date2) {
  // Convert both dates to UTC   
  const utcDate1 = date1.toUTCString(); 
  const utcDate2 = date2.toUTCString();
  // Now compare timestamps
  return utcDate1 - utcDate2;
}

Converting to UTC prevents incorrect date logic across timezones.


Conclusion


Handling dates and times is a key requirement for most web applications. Luckily, JavaScript’s built-in Date object provides a flexible API for creating, manipulating, and formatting dates programmatically.


In this post we covered core topics like instantiating Date objects, accessing date components, performing calculations, formatting dates for display, and using advanced libraries. We also explored practical integrations and some best practices around avoiding common date-related pitfalls.


Robust date handling forms the foundation of features like calendars, reminders, user analytics, and more. JavaScript’s Date object equips developers with the basic tools to build these experiences effectively. But additional libraries and specifications continue to evolve and refine working with dates in client-side code.