Reputation: 671
I have datetime(yyyy-MM-ddTHH:mm:ss), timezone offset value (K i.e -/+HH:mm) and country name and want to fetch IANA format ZoneId from these values in my web API.
Eg :
public static string FetchZoneID(string dateTime, string offset, string countryName)
{
//fetch zoneID
return zoneId;
}
for values
dateTime = "2020-02-06T06:11:01", offset = "+13:00", countryName = "New Zealand"
I should get
zoneId = "Pacific/Auckland"
and for values
dateTime = "2020-05-06T06:11:01", offset = "+12:00", countryName = "New Zealand"
I should get (due to DST)
zoneId = "Pacific/Auckland"
Currently using NodaTime, I was able to fetch all zoneIds for a particular country, but unable to figure out on how to filter these based on datetime and offset values.
var zoneIds = TzdbDateTimeZoneSource.Default.ZoneLocations.Where(x => x.CountryName == countryName)
.Select(x => x.ZoneId);
Can someone help me on this?
Note: In case of multiple zoneIds being eligible for the given offset, the first value would be used.
Upvotes: 1
Views: 1699
Reputation: 241808
I'll change your method signature slightly, and show how you can a list of all possible time zone ids for a given country where the offset matches for a particular local date and time:
public static ICollection<string> FetchZoneIds(OffsetDateTime dateTime, string countryCode)
{
return TzdbDateTimeZoneSource.Default.ZoneLocations
.Where(x => x.CountryCode == countryCode)
.Select(x => dateTime.InZone(DateTimeZoneProviders.Tzdb[x.ZoneId]))
.Where(x => x.Offset == dateTime.Offset)
.Select(x => x.Zone.Id)
.ToList();
}
Here's a little test method to illustrate calling with string inputs and dump to the output:
private static void Test(string dtoString, string countryCode)
{
Console.WriteLine($"{dtoString} ({countryCode})");
var offsetDateTime = OffsetDateTimePattern.GeneralIso.Parse(dtoString).Value;
var zoneIds = FetchZoneIds(offsetDateTime, countryCode);
foreach (var zoneId in zoneIds)
{
Console.WriteLine(zoneId);
}
Console.WriteLine();
}
Your first examples gives the single expected result:
Test("2020-02-06T06:11:01+13:00", "NZ");
2020-02-06T06:11:01+13:00 (NZ)
Pacific/Auckland
So does your second example:
Test("2020-05-06T06:11:01+12:00", "NZ");
2020-05-06T06:11:01+12:00 (NZ)
Pacific/Auckland
But look what happens here:
Test("2020-11-01T01:00:00-05:00", "US");
2020-11-01T01:00:00-05:00 (US)
America/New_York
America/Detroit
America/Kentucky/Louisville
America/Kentucky/Monticello
America/Indiana/Indianapolis
America/Indiana/Vincennes
America/Indiana/Winamac
America/Indiana/Marengo
America/Indiana/Petersburg
America/Indiana/Vevay
America/Chicago
America/Indiana/Tell_City
America/Indiana/Knox
America/Menominee
America/North_Dakota/Center
America/North_Dakota/New_Salem
America/North_Dakota/Beulah
Importantly, note that there are entries for both Eastern Time and Central Time in the results, the main ones being America/New_York
and America/Chicago
. How can that be?
No, it's not a bug. You can verify it here. In the US, daylight saving time doesn't happen all at once. It goes one time zone at a time from the east to the west. So when the fall-back transition takes place in the Eastern time zone (2:00 EDT becoming 1:00 EST), the Central time zone is still at 1:00 EDT. It doesn't transition for another hour. In other words, it's 1:00 with a UTC-5 offset in both EST and CDT at the same time.
If you don't care about such things, sure you could just do a .FirstOrDefault()
(the default being a null
string when there is no match). But you may indeed encounter edge cases like this one.
Upvotes: 1