How to get list of timezones in NodaTime - localization

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.

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 :(

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.

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

Related

TimeZone name / abbreviation from offset

I'm starting with a GMT offset in seconds, and I want the name of the corresponding time zone. I'm saying:
let offset = -28800
let tz = TimeZone(secondsFromGMT: offset)
let tzname = tz?.localizedName(for: .standard, locale: Locale.current)
I've tried many ways of getting tzname but all I ever get is GMT-05:00. That's not what I want. I'm hoping for something like "Eastern Standard Time" or "EST". Is there a way to get it?
I do not want to pass through some sort of reverse geocoding. I expect the system simply to hand me the answer. Other responses to this sort of question on Stack Overflow seem to indicate that that's what it ought to do, but it isn't doing it.
You cannot use the seconds offset from GMT, alone, to uniquely determine the timezone abbreviation. There is not a one-to-one correspondence between offsets and timezones.
This probably isn't going to be satisfying, but you can get a list of matching timezones by iterating through the knownTimeZoneIdentifiers and find a list of matching time zones:
let abbreviationsAndIdentifiers = TimeZone.knownTimeZoneIdentifiers
.compactMap { TimeZone(identifier: $0) }
.filter { $0.secondsFromGMT() == -28800 }
From there, you can use map to grab either abbreviation(for:), identifier or localizedName(for:locale:) to get PST, America/Los_Angeles or Pacific Standard Time for -28800, respectively. Obviously, the above may return a variety of different matches depending on the offset and time of year.
A few caveats for future readers:
Timezone abbreviations are not unique. See https://en.wikipedia.org/wiki/List_of_time_zone_abbreviations and you’ll see the same three letter abbreviation mapping to completely different time zones. E.g. CST can mean “Central Standard Time” (in North America), “Cuba Standard Time” or “China Standard Time”.
Be wary about the fact that an offset from GMT of -28800 will result in different timezones depending upon the time of the year. E.g. -28800 will return one set of timezone matches in January and another set in July because of daylight savings. Consider using secondsFromGMT(for:), specifying the date, instead, to remove any ambiguity.

get time of Different Timezone

My task: I am going to run a contest world wide at my website. A problem setter will set problems from a specific area of the world setting a time and date of starting time of the contest. I have to show that time correctly all over the world so the the contest starts at a time everywhere of the world.
My Idea : I planed to get the time from the problem setter of his time zone using server site language like php time(), & will store to database converting to timezone= zero (0). And who are going to attend the contest I'll just add hour(s) of that time zone with my database time.
Need help: I have no Idea how to convert that timestamps to timezone 'zero', even how can I get the ±hour(s) of current timezone?
Thank you...
Step 1:
Let the user choose his timezone. You could fill a dropdown with values from this site: http://php.net/manual/en/timezones.php
Step 2:
Convert the timezone to servertime
$timezone_client = new DateTimeZone('America/Denver');
$timezone_server = new DateTimeZone('Pacific/Nauru');
$datetime = new DateTime('2013-01-25 12:00:00', timezone_client);
$datetime->setTimezone($timezone_server);
echo $datetime->format('Y-m-d H:i:s');
Timezone 0 = "UTC" (sometimes called GMT)
Your system / language will have a Timezone class, which provides difference to GMT/UTC

User friendly timezone names from tz database format

I have timezones in the following array format:
'America/New_York' => '(GMT-05:00) Eastern Time (US & Canada)',
'Europe/Lisbon' => '(GMT) Greenwich Mean Time : Lisbon',
etc.
How do I go about displaying a user-friendly summer/daylight savings time dependent timezone identifier to the user?
For example, displaying the time now in New York would append "(EDT)" to the time, which would make sense for local users. I want to avoid having to display ((GMT-05:00) Eastern Time (US & Canada)) or just (GMT-05:00), which isn't strictly accurate all year round.
Ideally then, is there a web service/database that can take a tz string in the format "America/New_York", and a timestamp as paramters and return the abbreviation in the formats here?
strftime's %Z format specifier gives you this abbreviation. You didn't say what programming language you are using, but most programming languages give you access to strftime in one way or another.
Python:
import pytz
from datetime import datetime
here = pytz.timezone('Asia/Tokyo')
print here.localize(datetime.utcnow()).strftime("%Z")
there = pytz.timezone('America/Montreal')
print there.localize(datetime.utcnow()).strftime("%Z")
PHP:
date_default_timezone_set("Asia/Tokyo");
echo strftime("%Z");
date_default_timezone_set("America/Montreal");
echo strftime("%Z");

Problem in getting DST time?

I am trying to get the time of other GMT value by using
Calendar c1 = Calendar.getInstance(TimeZone.getTimeZone(gmt));
but how can i get the DST time at that time zone.
The TimeZone class provides a getDSTSavings() method for a specific TimeZone Object. (JavaDoc: "Returns the amount of time to be added to local standard time to get local wall clock time.")
The Calendar interface provides two getOffset() methods, which let you find out the offset from UTC. (JavaDoc: "Returns the offset of this time zone from UTC at the specified date. If Daylight Saving Time is in effect at the specified date, the offset value is adjusted with the amount of daylight saving. ")
please see this piece of code to grok the complicated ways of java time:
#Test
public void testDST() {
final TimeZone met = TimeZone.getTimeZone("MET");
Calendar gc = new GregorianCalendar(met);
final long timeInMillis = gc.getTimeInMillis();
final long gmtTime= timeInMillis-(gc.getTimeZone().getOffset(timeInMillis));
final Date gmtDate = new Date(gmtTime);
System.out.printf("%-40s: %tc\n%-40s: %tc\n%-40s: %tc\n%-40s: %d\n%-40s: %d",
"new Date() (local timezone)",new Date(),
"UTC", gmtDate ,
"now from Calendar with TC GMT+02:00",gc,
"zoneoffset",gc.get(Calendar.ZONE_OFFSET),
"dst savings",met.getDSTSavings());
}
You can also define your own SimpleTimeZone and provide custom DST rules, however, i have not found out how to get this information from the predefined TimeZones.
You should also be aware, that if TimeZone.getTimeZone(TZName) does not find the specified timezone, it does not throw an exception, but it just uses GMT, which can cause major misunderstandings.
You can find all this information (and a lot more) in javadoc for Calendar, TimeZone, Date, etc.
There are few methods available in java.util.TimeZone to get Daylight Saving Time. Please check out the BlackBerry Java Docs page.

How to compare dates independent of current culture in .NET

I hardcode a trial expiration date in my .net 2.5 app. how do I compare it with the user's system date such that the comparison is accurate regardless of the user's culture settings?
DateTime maxTrialDate = DateTime.Parse("11/17/2020", new System.Globalization.CultureInfo("en-US"));
DateTime curDate = DateTime.Parse(DateTime.Now.ToShortDateString(), new System.Globalization.CultureInfo("en-US"));
//the next line of code uses the DateDiff method to compare the two dates -dont recall its //exact syntax.
On my XP machine the above works if the control panel regional setting for datetime is en-US, but if I change it to en-AU, then the above code that sets curDate fires a FormatException "Date is not in a correct string format"
If you avoid using strings to represent the dates, you will not encounter this problem:
DateTime maxTrialDate = new DateTime(2020, 11, 17);
if (DateTime.Now.Date > maxTrialDate)
{
// expired
}
The DateTime is created by explicitly defining the day, month and year components, so the regional settings will not confuse matters.
What about just using CultureInfo.InvariantCulture all over the place?
You can use System.Globalization.CultureInfo.InvariantCulture
If I remember correctly, in most places outside the US, the standard date format is dd/mm/yyyy, rather than the US standard of mm/dd/yyyy. It might be that when trying to parse the date, it believes the 17 is the month, which is an invalid month, thus causing the error.
Why are you using the Parse method if you are hardcoding expiration date just compare it to
DateTime.now
The FormatException is expected since you explicitly ask the parser to use en-US.
Try calling the one-argument overload of DateTime.Parse(), or alternatively, if you really want to use the two-args overload (*cough*FxCop*cough*), something like:
using System.Globalization;
DateTime.Parse("11/17/2020", CultureInfo.CurrentCulture);

Resources