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

本文关键字:时间 日期 转换 UTC 何使用 Nodatime 时区 | 更新日期: 2023-09-27 18:33:17

我正在使用一个函数,该函数正在从外部服务器通过互联网获取日期时间。这是我用来获取日期和时间而不依赖于用户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 图书馆将返回该时区的本地日期和时间。

只是指导我如何实现它。 我访问了这个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();接下来我尝试根据我的第一个 UTC 时间获取不同时区的本地日期和时间,但代码返回了伦敦的错误时间。 我想我弄错了代码。 任何人都可以看到和帮助。 谢谢

编辑 2

我想通过野田时间图书馆实现的同样的事情。

    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时间服务器并获取UTC时间。

                       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();正在返回UTC日期时间。不是UTC时间吗?

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

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

您的GetFastestNISTDate函数使用日间协议 - 该协议基本上已弃用,并且不适用于机器交互,因为它的结果没有特定的格式。 甚至NIST的文档也强烈鼓励用户使用NTP而不是白天。

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

为了使事情变得更容易,我已将此客户端实现为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,你将在代码清晰度方面获得最大的好处。