4

How do I get a list of "time zones" from NodaTime such that I can make a UI like the below for my users to choose from?

I want to show the UTC offset and then the appropriate cities/countries/locations. It doesn't need to be exactly like the below, but you know, something close.

DateTimeZone doesn't have a name property, and ToString()ing produces duplicates (from the list of Ids from IDateTimeZoneProvider).

I see you can go from ~countries to zones, with TzdbDateTimeZoneSource.Default.ZoneLocations, but thats also not exactly what I'm looking for. I can see how I can cobble these two data sources together, but this feels like a solved problem I shouldn't be reinventing.

Example list

Matt Johnson-Pint
  • 230,703
  • 74
  • 448
  • 575
Andrew Bullock
  • 36,616
  • 34
  • 155
  • 231

3 Answers3

3

Noda Time doesn't currently provide user-oriented strings for time zones, no.

The best source of data for that is CLDR. We have a long-standing issue for this, but unfortunately it's fundamentally tricky. At some point I'd like to get back to it, but I haven't found time yet :(

You can use the Onism.Cldr project to access CLDR data. You'll need to understand how the CLDR data works in two respects though:

  • The time zone data structures such as metazones
  • The text data structures that allow you to get a particular string resource in the user's chosen language

Apologies that the answer at the moment is really just "No, there's nothing out of the box" - but that's the reality :(

Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
3

You can get a list of display names and their corresponding IANA time zone ids, suitable for building a dropdown in the way you described, using my TimeZoneNames library. The resulting IDs are compatible with NodaTime's TZDB provider.

// You can either hardcode the language (ex: "en-US"), or get it from .NET globalization:
var languageCode = CultureInfo.CurrentUICulture.Name;

// Then get the names, as a list of key/value pairs
var list = TZNames.GetDisplayNames(languageCode, useIanaZoneIds: true);

// Use them as you wish.  For example:
foreach (var name in list)
{
    Console.WriteLine($"{name.Key} = \"{name.Value}\"");
}

Output (truncated):

Etc/GMT+12 = "(UTC-12:00) International Date Line West"
Etc/GMT+11 = "(UTC-11:00) Coordinated Universal Time-11"
America/Adak = "(UTC-10:00) Aleutian Islands"
Pacific/Honolulu = "(UTC-10:00) Hawaii"
Pacific/Marquesas = "(UTC-09:30) Marquesas Islands"
America/Anchorage = "(UTC-09:00) Alaska"
Etc/GMT+9 = "(UTC-09:00) Coordinated Universal Time-09"
America/Tijuana = "(UTC-08:00) Baja California"
Etc/GMT+8 = "(UTC-08:00) Coordinated Universal Time-08"
America/Los_Angeles = "(UTC-08:00) Pacific Time (US & Canada)"
America/Phoenix = "(UTC-07:00) Arizona"
America/Chihuahua = "(UTC-07:00) Chihuahua, La Paz, Mazatlan"
America/Denver = "(UTC-07:00) Mountain Time (US & Canada)"
America/Guatemala = "(UTC-06:00) Central America"
America/Chicago = "(UTC-06:00) Central Time (US & Canada)"
Pacific/Easter = "(UTC-06:00) Easter Island"
...

The display names are sourced from Windows language packs. The IDs are translated from Windows to IANA through CLDR. If you want Windows IDs instead, you can set useIanaZoneIds to false (or omit it).

See also Methods for listing time zones and the Acknowledgements in the TimeZoneNames docs.

Matt Johnson-Pint
  • 230,703
  • 74
  • 448
  • 575
1

You can consider using GeoTimeZone Nuget Package to get the IANA timezone id by location i.e latitude and longitude for example

// using coordinates for a place in London use GeoTimeZone Library
string tz = GeoTimeZone.TimeZoneLookup.GetTimeZone(50.4372, -3.5559).Result; // Europe/London

DateTimeZone dateTimeZone = DateTimeZoneProviders.Tzdb.GetZoneOrNull(tz);

//You can get the UTC timeoffset at any instant possibly like this
Offset offset = dateTimeZone
            .GetUtcOffset(SystemClock.Instance.GetCurrentInstant());

Console.WriteLine(offset); //+01
Chitova263
  • 719
  • 4
  • 13