How to get the user’s timezone in JavaScript with Edge Functions
Tags: webdev, javascript, tutorial, deno
Published: 2022-12-12 10:50:30

In this vast, virtual and remote-first world, where we work, socialize and live our lives across timezones, it’s often helpful if dates and times are formatted and adapted according to different locales and timezones. Attending a virtual conference in the US but you’re located in the UK? Scheduling a call with a friend half way around the world? You most definitely want to view the event schedules in your timezone! 

Unfortunately, adapting dates and times according to timezones can prove to be *extremely* tricky. On top of accounting for timezone offsets from UTC (Coordinated Universal Time) — which can vary even if locations are on the same longitude(!) — timezones also change at various points throughout the year due to daylight savings time. And the time of year in which timezones shift also varies depending on location! And this is also subject to change 😅! Thankfully, JavaScript provides us with a nice little library of tools to work with dates and times.

## How to adapt and localize times in the browser with JavaScript

To adjust a date by timezone in JavaScript, you can use the Date object and its `toLocaleString()` method.

```javascript
// create a new Date object with the current date and time
var date = new Date();

// use the toLocaleString() method to display the date in different timezones
const easternTime = date.toLocaleString("en-US", {timeZone: "America/New_York"}));
const londonTime = date.toLocaleString("en-GB", {timeZone: "Europe/London"}));
```

You can also use the `Intl.DateTimeFormat()` method to localize the date and time and format it in a specific way, such as using a 24-hour clock or displaying the timezone abbreviation.

```javascript
// create a new Date object with the current date and time
var date = new Date();

// create a DateTimeFormat object with specific options
var dateFormat = new Intl.DateTimeFormat("en-US", {
	timeZone: "America/New_York",
	timeZoneName: "short"
});

// use the format() method to display the date and time in the specified format
// (e.g. "12/8/2020, EST")
const formatted = dateFormat.format(date);
```

## The problem with adapting and localizing times in the browser

Whilst using JavaScript in the browser is a good solution, there are — as usual! — some drawbacks. Most notably, users might see a flash of un-personalized content (FLUNP™️ — please send all credit for this fun acronym to [Phil Hawksworth](https://ntl.fyi/3UOmCTI)) before the JavaScript kicks in, or they might not see a localized date at all if JavaScript fails to load.

The traditional solution to this problem would be to perform any conditional logic on a server and deliver an adjusted and formatted date and time to the client at request-time. However, if you’re building a mainly static site, you probably don’t want to introduce a server just for the purposes of avoiding *potential* client-side drawbacks.  

But I have some great news for you! ***Timezone data is now available in Netlify Edge Functions***, removing the need to use *any* client-side JavaScript to successfully localize dates and times *or* introduce a fully-fledged server. And what’s more, you can use all the JavaScript native Date APIs you’re already familiar with inside the edge function code. 

If you’re not yet familiar with Netlify Edge Functions, head on over to a [previous tutorial](https://ntl.fyi/3PjshOQ) which shows you how to add personalization to a static HTML project using an edge function from scratch. There’s also a handy template project that you can deploy to Netlify at the click of a button.

**The rest of this post assumes you’re familiar with Netlify Edge Functions and you’re using the Netlify CLI to develop and test your code locally.** Let’s do it 😎.

## Get timezone data from an HTTP request

In a new or existing project, create a new edge function file and configure it in your netlify.toml file. In this example, I want the edge function code to run on `index.html`.

```javascript
// netlify/edge-functions/localize-time.js

export default async (request, context) => {
 
};
```

```toml
# netlify.toml

[[edge_functions]]
  path = "/"
  function = "localize-time"
```

Just like in the browser, we’re going to use the JavaScript Date `toLocaleString()` method to adapt the date and time. We need two bits of information for this: the locale and the timezone. Assign the `accept-language` header from the `request` to a `locale` variable (and provide a sensible fallback), and grab the `timezone` data from `context.geo`.

```javascript
// netlify/edge-functions/localize-time.js
 
export default async (request, context) => {
  const locale = request.headers["accept-language"] || "en-GB";   
  const { timezone } = context.geo;
};
```

## Set up the HTML to be modified

In the HTML where you’re currently displaying a date and/or time, add a data attribute — `data-time="{YOUR_TIME}"` — to the HTML element. In this example I’m using the JavaScript ISO date format. The `Z` at the end of the ISO string denotes that the time is in UTC. We’re going to use HTMLRewriter to grab this value, adjust it according to the timezone data and `accept-language` header, and modify the HTML response.

```html
<!-- index.html -->

<span data-time="2022-12-09T12:00:00Z">2022-12-09T12:00:00Z</span>
```

## Format and localize a date with JavaScript in Deno

Import HTMLRewriter at the top of your edge function, and add the following code to modify and return the HTML. Customize the date/time result to your preferences using the [options parameter](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/DateTimeFormat/DateTimeFormat#options).

```javascript
// netlify/edge-functions/localize-time.js

 import { HTMLRewriter } from "https://ghuc.cc/worker-tools/html-rewriter/index.ts";

 export default async (request, context) => {
   const locale = request.headers["accept-language"] || "en-GB";
   const { timezone } = context.geo;

   // capture the HTTP response so we can modify it
   const response = await context.next();

   return new HTMLRewriter()
     .on("[data-time]", {
       element(element) {
         // get the date value as a string from the HTML data attribute
         const dateString = element.getAttribute("data-time");

         // convert the string to a JavaScript date
         const date = new Date(dateString);

         // use toLocaleString() with the locale from the request
         // and the timezone from context.geo
         const localizedTime = date.toLocaleString(locale, {
           timeZone: timezone,
           hour: "numeric",
           minute: "numeric",
           day: "numeric",
           weekday: "short",
           month: "short",
         });

         // modify the HTML element
         element.setInnerContent(`${localizedTime}`);
       },
     })
     // transform the original response!
     .transform(response);
 };
```

## How I personalize timezones on my website with Edge Functions

I use the code in this post on my personal website homepage, where I localize the time of my next Twitch stream so viewers know when to tune in!

![My website screenshot, showing my home page with a next Twitch stream section, showing the time in GMT](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/pffjar1mwjwjkfxs4h3z.png)

## Learn more about website personalization using Edge Functions

Explore more [ideas and personalization use cases for Netlify Edge Functions on the blog](https://ntl.fyi/3UOmCTI) and browse a library of examples for inspiration on our [Edge Functions Examples site](https://edge-functions-examples.netlify.app/). Happy coding! 👩🏻‍💻