34

Is there a way to check if timezone name valid or not in JavaScript without using external library?

When user enters timezone name in text field I want to verify whether zone is valid or not?

I know we can do it easily using moment-timezone library. But I don't want to use any extra library. I'm looking for pure JavaScript way.

isValidTimeZone(name) {
//return true/false  
}

isValidTimeZone('Asia/Colombo'); //returns true
isValidTimeZone('America/Los_Angeles'); //returns true
isValidTimeZone('MyTimeZone/ME'); //returns false
Matt Johnson-Pint
  • 230,703
  • 74
  • 448
  • 575
Pratap A.K
  • 4,337
  • 11
  • 42
  • 79
  • 1
    Time zones are not considered valid based on the friendly location name (as you show in your question), they are valid based on a time zone offset. https://stackoverflow.com/questions/22609927/regular-expression-timezone – Scott Marcus May 22 '17 at 14:39
  • User enters timezone name (ex: Asia/Colombo). Later I need to use this in Highcharts. So need to validate this. User will not enter +05:30. – Pratap A.K May 22 '17 at 14:41
  • What makes a time zone valid for you? Is `America/Anaheim` valid? Because I don't think you mean that anything in "Continent/City_Name" format is automatically valid. You must have some database to test against. – Álvaro González May 22 '17 at 15:00
  • Do you feel like maintaining [this data](https://github.com/moment/moment-timezone/blob/develop/data/packed/latest.json) yourself? Seems like a lot of trouble to go to in order to avoid using a library. – Joe Clay May 22 '17 at 15:00
  • If you don't want use an external lib then there's no magic but write a map yourself. Checkout https://github.com/dmfilipenko/timezones.json or moment-timezone for a reference. – rstar May 22 '17 at 15:07
  • 3
    They aren't just "friendly" names, they are identifiers in the tz database. The list is here: https://en.wikipedia.org/wiki/List_of_tz_database_time_zones – Matt Johnson-Pint May 22 '17 at 17:00

3 Answers3

64

In environments that fully support IANA time zone identifiers in ECMA-402 (ECMAScript Internationalization API), you can try using a time zone in a DateTimeFormat (or in the options of to toLocaleString) and it will throw an exception if it is not a valid time zone. You can use this to test for validity, but only in environments where it is supported.

function isValidTimeZone(tz) {
    if (!Intl || !Intl.DateTimeFormat().resolvedOptions().timeZone) {
        throw new Error('Time zones are not available in this environment');
    }

    try {
        Intl.DateTimeFormat(undefined, {timeZone: tz});
        return true;
    }
    catch (ex) {
        return false;
    }
}

// Usage:
isValidTimeZone('America/Los_Angeles') // true
isValidTimeZone('Foo/Bar') // false

If you cannot be assured of your environment, then the best way would be with moment-timezone

!!moment.tz.zone('America/Los_Angeles') // true
!!moment.tz.zone('Foo/Bar') // false

Of course, you could always extract your own array of time zone names (perhaps with moment.tz.names() and test against that.

taxilian
  • 14,229
  • 4
  • 34
  • 73
Matt Johnson-Pint
  • 230,703
  • 74
  • 448
  • 575
14

in typescript you could also do in a more cleaner way

    public static isValidTimezone(timezone: string): boolean {
            return moment.tz.zone(timezone) != null;
        }

you need to also import

import moment = require("moment-timezone");
Pravin Bansal
  • 4,315
  • 1
  • 28
  • 19
5

I took Matt Johnson-Pin solution, after writing unit tests I found if to pass undefined the function returns true. So I made small update:

export const isValidTimeZone = (tz: unknown): boolean => {
    try {
        if (!Intl || !Intl.DateTimeFormat().resolvedOptions().timeZone) {
            return false
        }

        if (typeof tz !== 'string') {
            return false
        }

        // throws an error if timezone is not valid
        Intl.DateTimeFormat(undefined, { timeZone: tz })
        return true
    } catch (error) {
        return false
    }
}

Thanks anyway I use this in production.

NGS
  • 181
  • 2
  • 2