3

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

最初,我计划完全使用谷歌等的时区网络服务来完成这项工作,但在查看了免费帐户中允许的请求数量以及获得付费帐户所涉及的成本之后,我觉得最好找到一个替代方案无需抵押房屋即可解决。

环顾四周,我发现了 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:经过进一步研究,我找到了这个解决方案,并且觉得它也可以像这样很好地工作:

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 都使用系统时钟来获取当前时间?假设系统时间设置不正确,那么由于我们对用户系统时间的依赖,任何时区转换都会简单地显示其他城市的错误时间。

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

4

2 回答 2

4

几点:

  • 避免使用DateTime.Now

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

  • 在野田时代,实现那SystemClock.Instance是一个IClock接口的实现。只要有可能,您应该针对接口进行编码,以便您可以根据需要替换单元测试中的实现。尽管在最简单的示例中,调用并没有SystemClock.Instance.Now,只是它没有那么可测试。

  • 至于使用哪个时区输入,这完全取决于您的应用程序要求。

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

      DateTimeZone tz = DateTimeZoneProviders.Tzdb.GetSystemDefault();
      
    • 如果您无法正确设置系统时区,则可以考虑使用其他一些输入源。

    • 你提到了GPS坐标。如果你有这个,也许来自移动设备,有解决方案可以将它解析到一个时区。 请参阅此处了解一些选项。野田时代在这方面帮不了你。

    • 您也可以考虑让您的应用程序的用户从下拉列表或地图中选择一个时区。这里这里有一些基于地图的 HTML/JS 时区选择器。(我不确定它们是否可以在基于 WinJS 的 Windows Store App 中工作,而且我不知道任何基于 XAML 的解决方案。)

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

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

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

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

  • 关于您提供的两个代码示例,它们做的事情略有不同,但请选择选项 2。它更干净,而且是纯野田时间。

于 2013-09-18T16:20:55.983 回答
2

您通常可以依靠时钟显示的准确本地时间。任何 Windows 机器都设置为与时间服务器通信,默认为 time.windows.com。用户会注意到与他家中其他时钟的差异。弄错夏令时转换日期当然是可能的。但是,您不想推翻用户的设置,他很可能住在靠近时区边界并选择退出 DST 的县或只是制定自己的规则的地方,例如美洲印第安部落地区。

对世界上偏远地区做出这样的决定是一个完全不同的蜡球。值得注意的是萨摩亚岛,它在 2011 年跨越时区,甚至跨越了从 UTC-11 到 UTC+13 的日期变更线。夏令时规则总是受到当地政治决定的影响,它们不会成为当地报纸的头条新闻。它确实有可能成为网络服务。将城市映射到时区本身就需要大量数据库。如果需要绝对准确性,那么您确实需要服务。

于 2013-09-18T13:49:51.080 回答