Getting Personal With Dates and Times

By mandclu, Mon, 01/02/2023 - 09:12
Simple clock face, without numbers

Conversations with other people in the Drupal community, and related communities, has been a continued source of inspiration for me. Back in September, in a discussion at the San Francisco Drupal Users Group, someone mentioned a Backdrop module that uses Javascript to automatically format dates and times in the timezone of any visitor using Javascript. It seemed like a really interesting idea, and I wondered if there was something in its approach I might be able to bring to Smart Date. But it was a busy time, and I noted it down, but forgot about it.

It was during the recent Drupal 10 Launch Party that I was reminded about the idea of using Javascript to format dates, so they would be automatically in any visitor's timezone. The same idea had been implemented effectively for that site's schedule, which was a terrific fit for a global audience.

The script for that site worked great, but wasn't entirely aligned with what I wanted to create for Smart Date. For one thing, that approach made a site entirely dependent on JS. Load the home page in a browser with Javascript disabled, and no dates or times show at all. I've always been a big believer in having sites "degrade gracefully" whenever possible.

For a while now, the Smart Date module I maintain has had the ability to generate HTML5 time wrappers around the output, as an SEO best practice. It occurred to me that I could use these as the target for Javascript timezone conversion, in a process that I will refer to as localization in the rest of this writeup.

These time elements already included a datetime attribute containing an ISO string representation of the date or time being displayed. I decided to add data attributes to pass through the format being applied, and the timezone of the original date markup, so the JavaScript could skip any dates that were already in the visitor's timezone.

A Word About Formatting

The Backdrop module that has been my first source of inspiration, as well as the Drupal 10 Party site that later pushed me into going down this road, both relied on native Javascript formatting of the dates.

My concern with this approach was that if a visitor's browser had Javascript disabled, they wouldn't see the dates and times at all. This could also be caused by a Javascript error elsewhere on the page. Finally, if my solution was used on a site with a ton of Javascript, then the rendering of dates wouldn't happen until somewhere within that process of the browser working its way through all of the page's Javascript payload, potentially leading to a temporarily broken experience, or even issues like Cumulative Layout Shift, which have SEO implications.

Instead, I decided to pass through the PHP date and time formatting strings that are used by Smart Date formats to render out parts of the final markup. This would allow the page to be rendered (and cached) using the default or event-specific timezone, but then have that converted when the page loads.

I found some reference Javascript to format a date using a PHP date string, and adapted it to my needs. For example, the reference script got day-of-the-week or month labels using arrays of hard-coded names, but I needed something that would work across languages. Fortunately, JavaScript has equivalent methods to generate the labels based on a specific locale, so the modified script to generating them using the locale of the current page.

Consider this example, without the localization (saved with the Los Angeles timezone):

Tuesday, December 13th 2022, 4 - 5pm PST (Wednesday, December 14th 2022, 12 - 1am UTC)

Now, with the localization (accessed from the Toronto timezone):

Tuesday, December 13th 2022, 7 - 8pm EST (Wednesday, December 14th 2022, 12 - 1am UTC)

In French, without the localization:

Mardi 13 décembre 2022 à 16 h - 17 h PST (Mercredi 14 décembre 2022 à 00 h - 01 h UTC)

Also in French, but with the localization:

mardi 13 décembre 2022 à 19 h - 20 h UTC−5 (Mercredi 14 décembre 2022 à 00 h - 01 h UTC)

There are some differences worth pointing out in how Javascript and PHP handle the translations. Generally speaking the French language tends to capitalize much less than English does, but PHP seams to capitalize the first letter of the formatted date string, effectively treating it as sentence case. Also, Javascript translates the timezone code so we see UTC-5 instead of EST. In Canada, we would want to see HNE instead (for Canadian French), but to do that we would need to set the page's language code to "fr-CA" instead of "fr".

Comparing Timezones

The easiest way to compare timezones in Javascript is using the getTimezoneOffset method, but the challenge is that PHP and JS have very different ways of representing timezone offsets. In the end I decided it would be best to do the complex conversion logic on the server side (where it could be cached across visitors) to make the comparison faster in the client side script.

An Opt-In Configuration Option

I debated about implementing this new functionality as an entirely new field formatter, but ultimately decided that since the changes required were relatively minor, it could be added to the existing formatter as a configuration option.

Since the new localization relies on the time wrappers, existing sites using Smart Date won't see the new configuration option until the time wrappers option is enabled. I decided to leave the option as opt-in, so it won't impact existing sites unless site builders decided it's needed.

The screen to configure a Smart Date formatter, showing the new configuration option.
The new configuration option is visible in the Smart Date formatter configuration screen when the "Add time wrapper" option is enabled.

The Result

Based on initial testing, the new localization works seamlessly. On my (admittedly simple) test site, there was no visible lag on page load in order to see the localized times. I'm looking forward to hearing about how site owners find it works across a broader range of applications. Also, the Drupal community has consistently been an excellent source of inspiration on how projects can be even better, so I'm looking forward to hearing ideas about how this new client-side localization can be improved to meet even more use cases. This new functionality is included in a new release for Smart Date, so I hope you'll try it out and let me know how it work for you.



Restricted HTML

  • Allowed HTML tags: <a href hreflang> <em> <strong> <cite> <blockquote cite> <code> <ul type> <ol start type> <li> <dl> <dt> <dd> <h2 id> <h3 id> <h4 id> <h5 id> <h6 id>
  • Lines and paragraphs break automatically.
  • Web page addresses and email addresses turn into links automatically.