Sunday, September 19, 2021

Time Zone Conversion with Luxon and JavaScript

Did you know that every time you adjust your clock forward or backward for Daylight Savings Time (assuming your region follows it), you’re performing a Time Zone Conversion? In my case, I’m converting between Eastern Standard Time (EST) and Eastern Daylight Time (EDT). In fact, that’s what Time Zone Conversion is all about: adjusting your clock(s) or watch(es) according to a different time zone. It’s the same process you go through when traveling between time zones. You need to ask yourself, “what time is it now where I am going?”

Using Luxon, there are really two ways to go about it: you can either set the date and time to the new time zone or, you can determine the difference between the two time zones and adjust accordingly. While the second option may sound like the more difficult option, in JavaScript, it’s really not. I’ll prove it by taking the demo that we worked on in the Parsing Dates and Times Using Luxon tutorial and modify it to switch between the user’s local time zone and those of listed events, which take place in London, England.

Setting the Time on a Luxon DateTime Object

Before switching time zones, it helps if you’ve got time to change! To that end, I’ve added end dates to each event so that we can see both the start and end dates in our local time zone. You can see an example in the image below, along with the button that toggles between local and London time zones:

JavaScript and Luxon Time Zones

 

Setting the time is done in two steps:

  1. First, the time is parsed using the “h:mm a” time format string.
  2. Then, the times are combined with the start and end dates via Luxon’s versatile setter.

Here’s a code snippet that shows how the start and end dates and times are set:

var dayFormat    = "ccc, dd",
    inputFormat  = dayFormat + " LLL yyyy",
    timeFormat   = "h:mm a",
    $eventDates  = $('.eventDates'),
    startDates   = new Array($eventDates.length), 
    endDates     = new Array($eventDates.length),
    luxon        = luxon.DateTime,
    LONDON_TIMEZONE = 'Europe/London';

$eventDates.each(function(index) {
  var $this      = $(this),
      eventTimes = $this.siblings('span').text().split(' - '),
             // remove extra newlines and spaces in source
      eventDates = $this.text().replace(/\n\s+/,' ').split(' - '),
      startTime  = luxon.fromString(
                     eventTimes[0].trim(), timeFormat, {zone: LONDON_TIMEZONE}
                   ),
      startDate;

  // check if date range
  if (eventDates.length === 1) {
    startDate = eventDates[0];
  } else if (eventDates.length === 2) {
    startDate   = eventDates[1].replace(/[a-zA-Z]{3}, \d{2}/, eventDates[0]);
    var endTime = luxon.fromString(
                    eventTimes[1].trim(), timeFormat, {zone: LONDON_TIMEZONE}
                  );
    
    endDates[index] = 
      luxon.fromFormat(eventDates[1], inputFormat, {zone: LONDON_TIMEZONE})
        .set({hour: endTime.hour, minute: endTime.minute});
  }
  startDates[index] = 
      luxon.fromFormat(startDate, inputFormat, {zone: LONDON_TIMEZONE})
        .set({hour: startTime.hour, minute: startTime.minute});
});

Looking at the above code, you’ll notice that we are using the “Europe/London” time zone. I specifically chose events in the London area, thinking that these would be in UTC. I was mistaken because, like my home province in Ontario, Canada, London observes Daylight Savings Time. Hence, while it is identical to UTC in Winter, London has a GMT offset of +1 during the summertime.

Localizing a Luxon Date

Having created our dates with the correct “Europe/London” time zone, we can now switch time zones to our local one. In the button click handler, we can then check the current time zone of each start date:

$('#btnTimezone').click(function() {
  if (startDates[0].zoneName === LONDON_TIMEZONE) {
    $(this).text("View Dates in Your Time Zone ('" + startDates[0].zoneName + "')");
    //convert event dates to local time zone...
  } else {
    $(this).text("View Dates in Original Time Zone ('" + startDates[0].zoneName + "')");
    //convert event dates to London time zone...
  }
});

Displaying DateTimes in the Specified Time Zone

Updating the event dates and times on the web page also consists of two steps. They are:

  1. Convert the dates to and from the local and London time zones.
  2. Display them in the same format as they were originally parsed.

The first step is amazingly easy; local dates and times may be procured via Luxon’s toLocal() method, while setZone() may be utilized to convert a DateTime object to any time zone by passing in the time zone string (‘Europe/London’ in our case).

As for the second step, it’s not much more difficult because the same format string that we used to parse the dates and times may be reused by toFormat().

In fact, the conversion code is so similar overall that I put it in its own function called toggleTimezone(). It accepts two arguments – one mandatory, the other optional. The first argument is the conversion function, aka toLocal() or setZone(). The second is the time zone string, which is only required when converting to London time. Here’s the complete toggleTimezone() code:

function toggleTimezone(conversionFunction, timezone) {
  // wrap the timezone in an array
  timezone = Array.prototype.slice.call(arguments, 1);
  $eventDates.each(function(index) {
    var $eventDays = $(this),
        startDate  = conversionFunction.apply(startDates[index], timezone),
        $startEndTimes = $eventDays.siblings('span'),
        dateText = '',
        timeText = startDate.toFormat(timeFormat);

    //update the start date
    startDates[index] = startDate;

    if(endDates[index]) 
      var endDate = conversionFunction.apply(endDates[index], timezone);
      dateText  = startDate.toFormat(dayFormat)
        + " - " 
        + endDate.toFormat(inputFormat);
      timeText += " - " + endDate.toFormat(timeFormat);
      //update the end date
      endDates[index] = endDate;
    } else {
      dateText = startDate.toFormat(inputFormat);
    }
    $eventDays.text(dateText);
    $startEndTimes.text(timeText);
  });
}

The JavaScript Function apply() method is employed to invoke the supplied Luxon conversion function. The timezone argument is wrapped in an array using Array slice() since apply() requires its arguments to be passed as an array.

Conclusion

In this tutorial, we enhanced the demo that we worked on in the Parsing Dates and Times Using Luxon tutorial by modifying it to switch between the user’s local time zone and those of listed events, taking place in London, England.

You can see the Pen Luxon Time Zone Demo by Rob Gravelle (@blackjacques) on CodePen.

Robert Gravelle
Rob Gravelle resides in Ottawa, Canada, and has been an IT guru for over 20 years. In that time, Rob has built systems for intelligence-related organizations such as Canada Border Services and various commercial businesses. In his spare time, Rob has become an accomplished music artist with several CDs and digital releases to his credit.

Popular Articles

Featured