使用 NodaTime 将特定国家/地区日期时间转换为 UTC

Ker*_*ros 5 c# nodatime

我想通过提供国家/地区代码,使用 NodaTime 将特定日期时间值转换为 UTC。

例如,国家是土耳其,国家代码是 TR,具体日期时间是“2016 年 2 月 5 日 7:45 PM”,那么可能是“2016 年 2 月 5 日 5:45 PM”吗?

另外我的窗户位置不是土耳其。

先感谢您?

Jon*_*eet 4

嗯,你不能只用国家代码来做到这一点 - 你需要一个时区。有些国家/地区有多个时区。

一旦您拥有时区DateTimeZone(通过 BCLTimeZoneInfo或来自 TZDB 时区提供商),您将:

  • LocalDateTime根据您获得的值构造 a ,例如用于LocalDateTimePattern解析文本
  • 致电LocalDateTime.InZoneLeniently(或类似的电话 - 稍后会详细介绍)以获取ZonedDateTime
  • 用于WithZone(DateTimeZone.Utc)将其转换为基于 UTC 的ZonedDateTime

InZoneLeniently关于、InZoneStrictly或 的部分InZone(DateTimeZone, ZoneLocalMappingResolver)是因为在 DST 转换期间,本地日期和时间可能会出现两次或根本不出现。有关详细信息,请参阅用户指南。

示例代码:

using System;
using NodaTime;
using NodaTime.Text;

class Test
{
    static void Main()
    {
        var text = "Feb 5, 2016 7:45 PM";
        var zone = DateTimeZoneProviders.Tzdb["Europe/Istanbul"];
        var pattern = LocalDateTimePattern.CreateWithInvariantCulture("MMM d, uuuu h:mm tt");
        var local = pattern.Parse(text).Value;
        var zoned = local.InZoneStrictly(zone);
        var utc = zoned.WithZone(DateTimeZone.Utc);
        Console.WriteLine(utc); // 2016-02-05T17:45:00 UTC (+00)
    }
}
Run Code Online (Sandbox Code Playgroud)

现在,为了从国家/地区代码查找时区,TZDB (IANA) 数据库附带了有关时区位置的信息,这些信息在野田时间中公开。例如,如果您有 ISO-3166 2 字母国家/地区代码,则可以使用:

using NodaTime;
using NodaTime.TimeZones;
using System.Linq;
...
var code = "TR"; // Turkey
var zoneId = TzdbDateTimeZoneSource.Default.ZoneLocations
                                   .Single(loc => loc.CountryCode == code)
                                   .ZoneId;
var zone = DateTimeZoneProviders.Tzdb[zoneId];
Run Code Online (Sandbox Code Playgroud)

Single如果有多个区域具有给定的国家/地区代码(或没有),则呼叫将会失败。

如果您要经常查找区域,您可能需要构建一个字典:

var zonesByCountryCode = TzdbDateTimeZoneSource.Default
   .ZoneLocations
   .GroupBy(loc => loc.CountryCode)
   .Where(g => g.Count() == 1) // Single-zone countries only
   .ToDictionary(g => g.Key, g => g.First());
Run Code Online (Sandbox Code Playgroud)