【问题标题】:Converting time between different time zones在不同时区之间转换时间
【发布时间】:2013-09-18 12:25:33
【问题描述】:

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

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

【问题讨论】:

  • 如果用户时间错误,那么他们可能不需要时间完全准确(或无效的窗口副本)。您可以随时将他们的时间与网络时钟进行一次比较。
  • @Sayse 作为一个时钟应用程序,即使系统设置不正确,用户也会希望它显示正确的时间。我收到了足够多的支持请求,存在这个问题,因此这个问题。与网络时钟比较是一种选择,但只是想知道是否有另一种方法。

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


【解决方案1】:

几点:

  • 避免使用DateTime.Now

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

  • 在 Noda Time 中,意识到SystemClock.InstanceIClock 接口的实现。只要有可能,您应该针对接口进行编码,以便您可以根据需要替换单元测试中的实现。尽管在最简单的示例中,调用SystemClock.Instance.Now 并没有错误,但它只是不那么可测试。

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

    • 如果您可以依赖系统设置到正确的区域,您可以使用检索它

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

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

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

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

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

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

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

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

【讨论】:

  • 谢谢马特。我将采用您建议的解决方案(提供时区下拉菜单)而不使用 Web 服务。顺便说一句,我看到你提供的一些代码来获取基于国家代码的时区列表:stackoverflow.com/a/17098904/537871 - 这似乎是让用户输入他的城市、从下拉列表中选择国家然后选择时区的好解决方案为所选国家/地区。
  • 当您说不使用 DateTime.Now 时需要快速澄清一下 - 即使在计时器中每秒更新的时钟应用程序中显示当前时间,这是否也适用?应该使用 DateTimeOffset.Now 代替吗?
  • 如果您所做的只是显示它,并且在设备本身上调用它,那么DateTime.Now 不会伤害您。但是,如果您可以将其调整到其他时区,或者对其进行任何数学运算,那么您应该改用DateTimeOffset.Now
【解决方案2】:

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

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

【讨论】:

  • 你所说的那个广泛的数据库是IANA TZDB。它被整合到 Noda Time 中,并且可以随着新 TZDB 版本的发布而频繁更新。大多数服务都基于相同的数据做出响应,但不一定像您在自己的应用程序中需要的那样频繁更新。
  • 谢谢汉斯。夏令时是要处理的 PITA,因此我正在考虑使用 Web 服务。由于涉及成本(以及响应速度),像 NodaTime 这样的离线解决方案似乎非常适合这种情况,因为它内置了数据库。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-04-15
  • 1970-01-01
  • 2016-11-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-03-05
相关资源
最近更新 更多