Recently, I worked on an Interview Scheduler project, and the client would like to have users view the date times in different United States Timezone, and of course, the default timezone should be based on the user's current location.
JavaScript came with stand built-in function, toLocaleString()
, which is very handy, and we don't need to rely on other third-party libraries, like moment.js.
It takes two parameters, locales
and, i.e., toLocaleString(locales, options)
, in this case, we can have timezone defined in the options, here is the code snippet:
const currentDate = new Date();
const timezone = "US/Eastern" // this has to be IANA Database Name
const currentDTFormatted = currentDate.toLocaleString("en-US", { timeZone: timezone });
Note: the timezone option has to be a valid IANA (Internet Assigned Numbers Authority) timezone database name. If you like me find IANA database is so hard to use, here is the JSON file you can download, that may fit 99.99% of what you need.
It's a bit surprising, there is no straightforward method in JavaScript to return the current locale IANA Timezone Database Name, here are some functions, we may use:
export const getMyIANATZ = () => {
return Intl.DateTimeFormat().resolvedOptions().timeZone;
};
// This returns "US/New-York" in my location
const currentDate = new Date();
const currentTZOffset = currentDate.getTimezoneOffset();
// this returns 240, which 240 mins / 60 = 4 hours on today (Daytime Savings)
This is not a reliable method to me, because" Daylight savings" prevent this value from being constant. i.e., If I run this function in Winter, I will get 300 instead of 240 when there is a Daytime Savings.
3. RegExp
‘date’ object has a method ‘toString()’ return a string containing Timezone information, so we can use RegExp to extract the timezone info:
export const getMyTZ = () => {
return new Date().toString().match(/\(([A-Za-z\s].*)\)/)[1];
};
However, it doesn't return the valid IANA database name. For example, the above code snippet returns “Eastern Daylight Time”.
Looks like the first solution, using Intl Object, is the best one, but it's not perfect, because it returns a specific location, for example, ‘US/New-York’ instead of ‘US/Eastern’. In my case, I would like the Timezone dropdown to show fewer options. For United States users, the following Timezones should be enough:
export const mainUSTZ = () => {
return [
{
key: "us-pacific",
text: "Pacific Time - US & Canada",
value: "US/Pacific",
},
{
key: "us-mountain",
text: "Mountain Time - US & Canada",
value: "US/Mountain",
},
{
key: "us-central",
text: "Central Time - US & Canada",
value: "US/Central",
},
{
key: "us-eastern",
text: "Eastern Time - US & Canada",
value: "US/Eastern",
},
{
key: "us-hawaii",
text: "Hawaii Time - US",
value: "US/Hawaii",
},
{
key: "us-alaska",
text: "Alaska Time - US",
value: "US/Alaska",
},
];
};
Just like the Calendly app, it only shows the main US Timezone
To achieve this UX, I wrote some custom functions:
import usTZs from "../data/usTZGrouped.json";
export const getMyIANATZ = () => {
return Intl.DateTimeFormat().resolvedOptions().timeZone;
};
export const getTZGroup = (ianatz = null) => {
const localTZ = ianatz ? ianatz : getMyIANATZ();
// fallback
let currentTZGroup = "US/Pacific";
usTZs.forEach((item) => {
if (item.name === localTZ) {
currentTZGroup = item.group;
}
});
return currentTZGroup;
};
In order to use those functions, the grouped US Timezones data is required, and it's available here.
With those functions, I build a demo page here.
Happy coding!