转换不同时区之间的时间

时间:2013-09-18 12:25:34

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

我正在构建一个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 :在进一步观察之后,我发现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.Now SystemClock.Instance.Now 来首先识别用户的系统时间,然后将其转换为所需的时区的城市时间。但是如果用户的系统没有设置到正确的时间会怎样?我相信(如果错误,请纠正我)DateTime.Now和SystemClock.Instance.Now都使用系统时钟来获取当前时间?假设未正确设置系统时间,那么由于我们依赖于用户的系统时间,任何时区转换都只会显示其他城市的错误时间。

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

2 个答案:

答案 0 :(得分:4)

有几点:

  • 避免使用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了解一些选项。 Noda Time在这方面无法帮助你。

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

  • 如果时钟的实际时间设置错误,除了尝试联系其他服务器以检索时间戳之外,您无法做很多事情。在大多数情况下,您应该依赖操作系统与时间服务器同步。

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

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

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

  • 关于您提供的两个代码示例,它们的功能略有不同,但请选择选项2.它更清晰,并且是纯粹的Noda Time。

答案 1 :(得分:2)

您通常可以依赖当地时间准确,如时钟所示。任何Windows计算机都设置为与时间服务器通信,默认为time.windows.com。用户会注意到他家中其余时钟的差异。让夏令时过渡日期错误肯定是可能的。但是你不想要否决用户的设置,他可能住在一个靠近时区边界的县,并选择退出夏令时或一个只是制定自己规则的地方,比如美洲印第安部落地区。 / p>

对世界上遥远的地方做出这样的决定是一个完全不同的蜡烛。值得注意的是萨摩亚岛,它在2011年跨越了时区,甚至超过了从UTC-11到UTC + 13的日期线。夏令时规则总是受到当地政治决策的影响,它们并不是当地报纸的新闻。一些可能性,它确实使它成为一个Web服务。将城市映射到时区本身就需要广泛的数据库。如果需要绝对的准确性,那么你确实需要一项服务。