如何使用不同的时区Nodatime将UTC日期和时间转换为当地时间

我正在使用从外部服务器通过互联网获取日期时间的function。 这是我用来获取日期和时间的function,而不依赖于用户的PC日期时间设置。

using NodaTime; using NodaTime.Text; using System.IO; using System.Globalization; public static DateTime GetFastestNISTDate() { var result = DateTime.MinValue; DateTime utcDateTime = DateTime.MinValue; // Initialize the list of NIST time servers // http://tf.nist.gov/tf-cgi/servers.cgi string[] servers = new string[] { "nist1-ny.ustiming.org", "nist1-nj.ustiming.org", "nist1-pa.ustiming.org", "time-a.nist.gov", "time-b.nist.gov", "nist1.aol-va.symmetricom.com", "nist1.columbiacountyga.gov", "nist1-chi.ustiming.org", "nist.expertsmi.com", "nist.netservicesgroup.com" }; // Try 5 servers in random order to spread the load Random rnd = new Random(); foreach (string server in servers.OrderBy(s => rnd.NextDouble()).Take(5)) { try { // Connect to the server (at port 13) and get the response string serverResponse = string.Empty; using (var reader = new StreamReader(new System.Net.Sockets.TcpClient(server, 13).GetStream())) { serverResponse = reader.ReadToEnd(); } // If a response was received if (!string.IsNullOrEmpty(serverResponse)) { // Split the response string ("55596 11-02-14 13:54:11 00 0 0 478.1 UTC(NIST) *") string[] tokens = serverResponse.Split(' '); // Check the number of tokens if (tokens.Length >= 6) { // Check the health status string health = tokens[5]; if (health == "0") { // Get date and time parts from the server response string[] dateParts = tokens[1].Split('-'); string[] timeParts = tokens[2].Split(':'); // Create a DateTime instance utcDateTime = new DateTime( Convert.ToInt32(dateParts[0]) + 2000, Convert.ToInt32(dateParts[1]), Convert.ToInt32(dateParts[2]), Convert.ToInt32(timeParts[0]), Convert.ToInt32(timeParts[1]), Convert.ToInt32(timeParts[2])); // Convert received (UTC) DateTime value to the local timezone result = utcDateTime.ToLocalTime(); //return result; return utcDateTime; // Response successfully received; exit the loop } } } } catch { // Ignore exception and try the next server } } //return result; return utcDateTime; } 

这个variable result有本地日期时间,但我需要使用Nodatime库,我将把我的本地日期时间变量result ,并指定不同的时区,Noda libraray将返回该时区的本地日期和时间。

只是指导我如何实现它。 我访问这个url但仍不清楚如何将Nodatime图书馆和本地时间从外部服务器整合在一起,以获得基于不同时区的另一个日期时间。

寻求帮助的一些示例代码谢谢

编辑

 var wc = GetFastestNISTDate(); var pattern = InstantPattern.CreateWithInvariantCulture("dd/MM/yyyy HH:mm:ss"); var parseResult = pattern.Parse(wc.ToString("dd/MM/yyyy HH:mm:ss", CultureInfo.InvariantCulture)); if (!parseResult.Success) throw new InvalidDataException("...whatever..."); var instant = parseResult.Value; var timeZone = DateTimeZoneProviders.Tzdb["Europe/London"]; var zonedDateTime = instant.InZone(timeZone); var bclDateTime = zonedDateTime.ToDateTimeUnspecified(); 

时区翻译不起作用。 我从这个函数GetFastestNISTDate();得到了正确的日期GetFastestNISTDate(); 然后我尝试根据我的第一个utc时间获取不同时区的本地日期和时间,但代码返回伦敦错误的时间。 我想我错了代码。 任何人都可以看到和帮助。 谢谢

编辑2

我想通过Nodatime图书馆实现的目标。

  var wc = GetFastestNISTDate(); TimeZoneInfo cstZone = TimeZoneInfo.FindSystemTimeZoneById("GMT Standard Time"); DateTime cstTime = TimeZoneInfo.ConvertTimeFromUtc(wc, cstZone); 

上面的代码给出了或多或少的正确时间。 告诉我如何使用nodatime库替换我的最后2行。 谢谢

编辑3

 var wc = GetFastestNISTDate(); Instant now = Instant.FromDateTimeUtc(wc); var timeZone = DateTimeZoneProviders.Tzdb["Europe/London"]; var zonedDateTime = instant.InZone(timeZone); var bclDateTime = zonedDateTime.ToDateTimeUnspecified(); 

@John告诉我上面的代码是可以的,因为你说

 Don't convert the UTC DateTime to a local version - it's pointless and confusing Use Instant.FromDateTimeUtc to convert a UTC DateTime to an instant GetFastestNISTDate() returning datetime instance and here we just create noda instance from utc datetime using like this code `Instant now = Instant.FromDateTimeUtc(wc);` 

它解决了这个问题。

编辑4

 @Matt Johnson : thanks a lot for redirecting me to a good library. i would definitely like to work with that library to achieve my task. before use your library i have some question. 
  1. 第1点

    你在这个例程中注意到了什么错误GetFastestNISTDate(); 例程查询几个NIST时间服务器并获取utctime。

      utcDateTime = new DateTime( Convert.ToInt32(dateParts[0]) + 2000, Convert.ToInt32(dateParts[1]), Convert.ToInt32(dateParts[2]), Convert.ToInt32(timeParts[0]), Convert.ToInt32(timeParts[1]), Convert.ToInt32(timeParts[2])); 

这个例程GetFastestNISTDate(); 回来了utcDateTime ….不是时候吗?

  1. 第2点

当我打电话给GetFastestNISTDate(); 例程我注意到这个例程有一段时间返回DateTime.MinValue ,这不是预期的结果。 我可以理解为什么会发生这种情况, because NIST time servers正忙或被阻止或当时发生超时。

  1. 点3如果我使用你当前的代码/库NodaTime.NetworkClock然后我想知道它将默认查询哪个NTP服务器?

如果我使用NodaTime.NetworkClock那么由于NTP server is busy/block或超时发生,有时候我可能会错误的日期或空日期吗?

编辑5

  var instant = NetworkClock.Instance.Now; var timeZone = DateTimeZoneProviders.Tzdb["Europe/London"]; var zonedDateTime = instant.InZone(timeZone); lbldate.Text = zonedDateTime.ToString("dd/MM/yyyy", CultureInfo.InvariantCulture); lbltime.Text = zonedDateTime.ToString("hh:mm:ss", CultureInfo.InvariantCulture); 

您的GetFastestNISTDate函数使用白天协议 – 基本上已弃用, GetFastestNISTDate用于机器交互,因为其结果不是特定格式。 即使是来自NIST的文档也强烈建议用户使用NTP而不是白天。

您可以在此处找到NTP客户端的简单C#实现。

为了NodaTime.IClock ,我将此客户端实现为NodaTime.IClock 。 代码在GitHub上。 只需从NuGet安装它:

 Install-Package NodaTime.NetworkClock 

然后就像使用SystemClock一样使用它:

 var instant = NetworkClock.Instance.Now; var timeZone = DateTimeZoneProviders.Tzdb["Europe/London"]; var zonedDateTime = instant.InZone(timeZone); 

您不应该将DateTime转换为字符串并返回 – 但您当前的问题是您将从服务器返回的UTC值转换为本地DateTime ,原因并非明显。 理想情况下,我建议更改GetFastestNISTDate()以返回Instant ,但假设您不能这样做:

  • 不要自己解析。 从响应中获取适当的子字符串,然后使用DateTime.ParseExact ,指定CultureInfo.InvariantCultureDateTimeStyles.AssumeUniversal
  • 不要将UTC DateTime转换为本地版本 – 这是毫无意义和令人困惑的
  • 使用Instant.FromDateTimeUtc将UTC DateTime转换为瞬间

代码的最后一部分(最后三行)没问题,但为什么你需要一个DateTime呢? 如果您可以使用Noda Time尽可能多地编写代码,那么在代码清晰度方面您将获得最大的好处。