在 C# 中使用国家名称、日期时间和时区偏移值获取 ZoneId

Get ZoneId using country name, datetime and timezone offset values in c#

我有日期时间(yyyy-MM-ddTHH:mm:ss)、时区偏移值(K 即 -/+HH:mm)和国家/地区名称,并且想从我的网站中的这些值中获取 IANA 格式的 ZoneId API.

例如:

public static string FetchZoneID(string dateTime, string offset, string countryName)
{        
//fetch zoneID    
return zoneId;
}

价值

dateTime = "2020-02-06T06:11:01", offset = "+13:00", countryName = "New Zealand"

我应该得到

zoneId = "Pacific/Auckland"

以及值

dateTime = "2020-05-06T06:11:01", offset = "+12:00", countryName = "New Zealand"

我应该得到(由于 DST)

zoneId = "Pacific/Auckland"

目前使用 NodaTime,我能够获取特定国家/地区的所有 zoneId,但无法弄清楚如何根据日期时间和偏移值过滤这些。

var zoneIds = TzdbDateTimeZoneSource.Default.ZoneLocations.Where(x => x.CountryName == countryName)
    .Select(x => x.ZoneId);

有人可以帮我解决这个问题吗?

注意:如果多个 zoneId 符合给定偏移量的条件,将使用第一个值。

我将稍微更改您的方法签名,并展示您如何可以列出所有 给定国家/地区的可能时区 ID,其中偏移量与特定本地日期相匹配和时间:

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();
}

这里有一个小测试方法来说明使用字符串输入调用并转储到输出:

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();
}

您的第一个示例给出了单一的预期结果:

Test("2020-02-06T06:11:01+13:00", "NZ");
2020-02-06T06:11:01+13:00 (NZ)
Pacific/Auckland

你的第二个例子也是:

Test("2020-05-06T06:11:01+12:00", "NZ");
2020-05-06T06:11:01+12:00 (NZ)
Pacific/Auckland

但看看这里发生了什么:

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

重要的是,请注意结果中有东部时间和中部时间的条目,主要是America/New_YorkAmerica/Chicago。怎么可能?

不,这不是错误。 You can verify it here。在美国,夏令时不是一下子就来的。它从东到西一次走一个时区。因此,当回退过渡发生在东部时区(2:00 EDT 变为 1:00 EST)时,中部时区仍为 1:00 EDT。它不会再过渡一个小时。换句话说,它 1:00 在 EST 和 CDT 中同时具有 UTC-5 偏移量

如果你不关心这些事情,当然你可以做一个.FirstOrDefault()(当没有匹配时默认是一个null字符串)。但你可能确实会遇到像这样的边缘情况。