Check If Today is Between Two Dates in JavaScript

Abstract image used to represent Check If Today is Between Two Dates in JavaScript
Image by Behnam Norouzi.

In Brief

Turn the start date, end date, and target date into comparable Date values, then decide whether the range includes its endpoints. Dateonly checks also need a clear timezone assumption, because parsing the same value locally can shift the result around midnight and change whether today appears inside the range.

Working with and manipulating dates is a longstanding and sometimes convoluted process in web development. In one of the very early versions of my website (from all the way back in 2001), I went to great lengths to rebrand the site based on the time of day, the weather conditions, and of course special dates such as Christmas.

Screenshot of the johnkavanagh.co.uk website from 2001 showing the Christmas theme, displayed automatically when the dates were right.

This was achieved using some fairly complex PHP attached to generated query parameters, producing a different version of the site CSS based on date and time. Obviously, with newer technology comes easier ways of achieving similar.

This current version of my site has been live for over two years now, and as the holidays come ever closer, I'm reminded that I haven't yet included an automated way to add a little festive cheer to the site around the holidays.

If you revisit in the coming days (between 20th December and 4th January as you'll see in the code examples below), you'll see the introduction of a nice animated snow effect. The same one that also displays when it (rarely) actually does snow here in Brighton.

Because this is all achieved clientside with React, it's relatively straightforward to compare the date today against a start and end date (using Date) and then trigger the festivities!


A brief overview of how Date works

Mozilla has some great and very detailed documentation on how Date and Date() work, but for the sake of this article, the pertinent details are:

The Date object is essentially a platformindependent representation of a single point in time. Date() returns either a Date object, or a string representation depending on whether it is called as a function or a constructor.

When called as a function, Date() returns a string that represents today's date and time:

Date()
//=> 'Thu Dec 08 2022 11:53:54 GMT+0000 (Greenwich Mean Time)'

When called as a constructor, Date() accepts a date in yyyy-mm-dd (as a string), and returns a Date object:

new Date('2022-12-25')
//=> Sun Dec 25 2022 00:00:00 GMT+0000 (Greenwich Mean Time)

When combined with the getTime() method, these return a number representing the milliseconds that have elapsed since the ECMAScript epoch: midnight at the start of January 1st, 1970 (UTC) equivalent to the UNIX epoch.

new Date('2022-12-25').getTime()
//=> 1671926400000

Putting Date to use

For this example, I'm treating the Christmas period as 20 December through 4 January in UTC. Dateonly ISO strings are parsed at midnight UTC, so I'll use those boundaries consistently. This gives every visitor the same interval; a localcalendar celebration would need local date construction instead.

  1. Store the start and end dates in milliseconds using the Date() constructor and getTime() method;
  2. Get the current time, again using new Date().getTime();
  3. Check that the current time is at or after the start and before the end;
  4. If so, today is between those two dates.
// 1
const christmasStart = new Date('2022-12-20').getTime();
const christmasEnd = new Date('2023-01-05').getTime();

// 2
const today = new Date().getTime();

// 3 & 4
const isChristmas = today >= christmasStart && today < christmasEnd;

Including the Boundary Dates

The example includes the start timestamp and excludes the end timestamp. Setting christmasEnd to midnight at the start of 5 January therefore includes all of 4 January, without needing to work out its final millisecond.

For other ranges, choose which exact boundary timestamps you want to include. These comparisons show the alternatives:

// Include only the start timestamp
const isChristmas = today >= christmasStart && today < christmasEnd;

// Include only the end timestamp
const isChristmas = today > christmasStart && today <= christmasEnd;

// Include both boundary timestamps
const isChristmas = today >= christmasStart && today <= christmasEnd;

These comparisons only affect the boundary timestamps themselves. If christmasEnd instead represented midnight at the start of 4 January, using <= would include that single instant, but not the remainder of the day.

For whole days, I find a startinclusive, endexclusive interval easier to reason about. The Christmas examples use 5 January as the exclusive end. Choose the dates and time zone to suit the behaviour you want, then keep that choice consistent throughout the calculation.


Making This Repeatable Each Year

You may have noticed in the code above, we're hardcoding the year in our christmasStart and christmasEnd constants. This is all well and good for this Christmas, but I'd like this to happen automatically each year rather than requiring an annual code edit.

For a UTC range, use getUTCFullYear() to read the year and getUTCMonth() to identify January. Month numbers start at zero. If today falls in January, the Christmas period started in the previous year.

new Date().getUTCFullYear()
//=> 2022

new Date('1999-12-31').getUTCFullYear()
//=> 1999

Use that Christmas year in the start date and the following year in the end date. Taking one reading of the current time also keeps the calculation consistent if it runs right across midnight:

const todayDate = new Date();
const christmasYear =
  todayDate.getUTCMonth() === 0
    ? todayDate.getUTCFullYear() - 1
    : todayDate.getUTCFullYear();

const christmasStart = new Date(`${christmasYear}-12-20`).getTime();
const christmasEnd = new Date(`${christmasYear + 1}-01-05`).getTime();
const today = todayDate.getTime();

const isChristmas = today >= christmasStart && today < christmasEnd;

The Wrap‑up

Using Date we can convert dates and times (either predefined or simply the date today) to a numerical representation, which it is then very straightforward to compare against.

Postscript

July 2026: Temporal reached Stage 4 in March 2026, but MDN still records limited browser availability. The Date examples above use UTC calendar dates and include 20 December through 4 January. For new code that needs dateonly values, time zones, or safer calendar arithmetic, check runtime support before choosing Temporal or a polyfill.

Untangling a delivery problem?

Send the symptoms, constraints, and affected routes. I'll help identify whether the issue sits in the application, platform, content model, deployment path, or search surface.