c# - 在不同时区之间转换时间

标签 c# windows datetime windows-store-apps nodatime

我正在构建一个 Windows 商店时钟应用程序来显示用户的当前时间以及世界各地不同城市的时间。

最初,我计划完全使用 Google 等的时区网络服务来完成此操作,但在查看了免费帐户中允许的请求数量和获得付费帐户所涉及的成本之后,我觉得最好找到替代解决方案,而不必抵押房屋。

四处搜索,我发现了 John Skeet 和团队的优秀 NodaTime 库。在浏览了文档和此处的 stackoverflow 之后,我的脑袋里仍然嗡嗡作响所有与日期时间和时区相关的术语和转换方法。不管怎样,我想我可以用 2 个选项来做到这一点:

选项 1:使用 DateTime.Now 获取当前系统时间,然后像这样使用 nodatime 获取其他区域的时间(基于 Matt Johnson 在回答 SO 上的另一个问题时提供的代码) :

DateTimeZone homeZone = DateTimeZoneProviders.Tzdb["Asia/Colombo"];
LocalDateTime homeTime = LocalDateTime.FromDateTime(DateTime.Now);
ZonedDateTime homeTimeInZone = homeTime.InZoneStrictly(homeZone);
TbTime1.Text = "Home time is: " + homeTimeInZone.ToDateTimeOffset();

DateTimeZone timeZone1 = DateTimeZoneProviders.Tzdb["Australia/Perth"];
ZonedDateTime timeZone1Time = homeTimeInZone.WithZone(timeZone1);
TbTime2.Text = "Timezone 1 time is: " + timeZone1Time.ToDateTimeOffset();

选项 2:进一步查找后,我发现 this solution并且觉得它也可以像这样很好地工作:

public ZonedDateTime GetTimeInTimeZone(string timeZone)
{
    // Timezone is olson timezone e.g. "Asia/Colombo"
    Instant now = SystemClock.Instance.Now;
    var zone = DateTimeZoneProviders.Tzdb[timeZone];
    ZonedDateTime zonedDateTime = now.InZone(zone);
    return zonedDateTime;
 }

现在让我试着回答这个问题:在上面的两个选项中,都依赖于 DateTime.NowSystemClock.Instance.Now 来首先识别用户的系统时间,然后将其转换为所需时区的城市时间。但是如果用户的系统没有设置正确的时间会怎样呢?我相信(如果错误请纠正我) DateTime.Now 和 SystemClock.Instance.Now 都在使用系统时钟来获取当前时间?假设系统时间设置不正确,那么由于我们依赖于用户的系统时间,任何时区转换都只会显示错误的其他城市时间。

在这种情况下,如何在不依赖系统时钟的情况下确定用户的当前时间?我应该恢复使用网络服务来使用纬度/经度获取用户的当前时区,还是使用 NodaTime 等可以离线工作的更好选择?谢谢。

最佳答案

几点:

  • 避免使用 DateTime.Now

    • 它已经转换为本地时区,因此在 DST 回退转换期间,结果可能不明确。
    • 如果您需要在不使用 Noda Time 的情况下获得准确明确的时刻,请使用 DateTime.UtcNow
    • 您还可以使用 DateTimeOffset.UtcNowDateTimeOffset.Now。当包含偏移量时,没有歧义。
    • 另请参阅 The Case Against DateTime.Now在我的博客上。

  • 在Noda Time中,实现SystemClock.InstanceIClock接口(interface)的实现。只要有可能,您应该针对接口(interface)进行编码,这样您就可以在需要时替换单元测试中的实现。尽管在最简单的示例中,调用 SystemClock.Instance.Now 没有任何错误,只是它不可测试。

  • 至于使用哪个时区输入,那完全取决于您的应用需求。

    • 如果您可以将系统设置为正确的区域,您可以使用

      检索它
      DateTimeZone tz = DateTimeZoneProviders.Tzdb.GetSystemDefault();
      
    • 如果您不能依赖正确设置的系统时区,您可以考虑一些其他输入源。

    • 您提到了 GPS 坐标。如果你有,也许来自移动设备,有一些解决方案可以将它解析为时区。 See here对于某些选项。这方面野田时代帮不了你。

    • 您还可以考虑让应用的用户从下拉列表或 map 中选择时区。有一些基于 map 的 HTML/JS 时区选择器 herehere . (我不确定它们是否可以在基于 WinJS 的 Windows 应用商店应用程序中运行,而且我不知道有任何基于 XAML 的解决方案。)

  • 如果他们时钟的实际时间设置错误,除了尝试联系另一台服务器以检索时间戳之外,您无能为力。在大多数情况下,您应该依赖已经与时间服务器同步的操作系统。

    • 如果您确实需要与外部服务同步,那将是一项挑战。您需要一些能够正确实现 NTP 的东西,包括测量和补偿传输延迟。这并不容易,可能需要一个外部库。我不知道有什么值得推荐的。

    • 访问 Web 服务并返回当前时间不一定像您想象的那样准确,因为这并不能补偿服务器向您传输该响应所花费的时间.

    • 如果您在带有 GPS 接收器的设备上运行,那么从技术上讲,它可以提供从 GPS 信号接收到的准确时间戳。我不确定它是否可以通过 Windows 应用商店 API 检索和使用。我在 MSDN 上查看了一些引用资料,但没有找到任何引用资料。

  • 关于您提供的两个代码示例,它们做的事情略有不同,但选择选项 2。它更简洁,并且是纯粹的 Noda Time。

关于c# - 在不同时区之间转换时间,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18872230/

相关文章:

c# - 在页面加载时检查用户身份验证

c# - 在 IIS 中部署时,复选框在 TreeView 控件的节点上不可见

c++ - 链接 Qt5.6 会产生找不到所需引用的错误

python - 使用 IDLE 运行与运行脚本

r - 使用 read_delim 解析分秒日期

javascript - 将 "simple"时区偏移量 (-7) 转换为 "full"偏移量 (-07 :00)

c# - 重载 == (当然还有 != )运算符,我可以绕过 == 来判断对象是否为 null

c# - 在 Unity 2D 中实现梯子

python - conda 在 windows 64 上安装 matplotlib 的 natgrid python 工具包

PHP将mysql查询字符串转换为mm :ss time format