【问题标题】:Determine Time Offset given Olson TZID and local DateTime?确定给定 Olson TZID 和本地 DateTime 的时间偏移量?
【发布时间】:2014-01-25 13:47:14
【问题描述】:

我需要根据事件的 Olson TZID 和事件的 DateTime 确定时间偏移

我想我可以在 Noda Time 的帮助下完成,但我是新来的,需要帮助 - 执行此任务的实际 API 调用序列示例。

我们正在使用和做什么的更多细节。

  1. 我们正在运行基于 ASP.NET + SQL Server 的网站。我们网站的用户输入并保存在不同地点发生的事件。对于每个事件的 Lat/Long 和 DateTime 以及(该事件的)时间偏移量,都属于必填字段。
  2. 数据录入有多种场景,有时先输入Lat/Long,有时先输入DateTime。系统允许从地址或地图点确定纬度/经度。在大多数情况下,我们希望 Time Offset 与 Lat/Long 保持一致,因为我们通常希望 DateTime 作为该事件的本地输入。
  3. 我们使用 SQL Server DateTimeOffset 字段来存储数据。
  4. 我们不想依赖第三方 Web 服务来确定偏移量,而是希望我们的系统来执行此操作。

我可以免费下载和使用任何必要的工具或数据。我已经从 http://efele.net/maps/tz/ 下载了 shapefile,并使用 Shape2SQL http://goo.gl/u7AUy 将它们转换为带有 TZID 和 GEOM 的 SQL Server 表。
我知道如何通过查询该表从 Lat/Long 获取 TZID
我需要再次根据 TZID 和 DateTime 确定时间偏移

【问题讨论】:

  • 我想我已经得到了 Jon Skeet 在 Noda Time Google Group goo.gl/I9unm0 上对我的问题的正确答案。不过,在这里提出这个问题和答案并没有什么坏处,因为其他人也可能会使用它。
  • 如果是这种情况,您可以自己回答问题,稍等片刻,接受。

标签: asp.net sql-server timezone-offset nodatime iana


【解决方案1】:

感谢 Jon Skeet 和 Matt Johnson 在 Noda Time Google Group http://goo.gl/I9unm0 上提供答案。 Jon 解释了如何在给定 Olson TZID 和 NodaTime LocalDateTime 值的情况下获取 Microsoft BCL DateTimeOffset 值。 Matt 指出了一个在给定 ZonedDateTime 的情况下确定 DST 是否处于活动状态的示例:What is the System.TimeZoneInfo.IsDaylightSavingTime equivalent in NodaTime?

我将写一篇博文总结我从 Lat/Long 获取 Olson TZID、将 DateTime 字符串解析为 LocalDateTime 并确定 DateTimeOffset 的经验。我将在那里展示 GetTmzIdByLocation(latitude, longitude) 和 GetRoughDateTimeOffsetByLocation(latitude, longitude) 方法的工作原理以及为什么我需要这两种方法(第一种方法不适用于海洋位置)。写完这篇文章,我会在这里添加评论。

注意,在下面的代码中解析 DateTime 字符串还不是最优的;正如马特在 Google Group 帖子(上面的链接)中解释的那样,使用 Noda Time 工具比使用 BCL 更好。在http://goo.gl/ZRZ7XP 上查看相关问题

我当前的代码:

public object GetDateTimeOffset(string latitude, string longitude, string dateTime)
{
    var tzFound = false;
    var isDST = false;

    var tmpDateTime = new DateTimeOffset(DateTime.Now).DateTime;
    if (!String.IsNullOrEmpty(dateTime))
    {
        try
        {
            // Note: Looks stupid? I need to throw away TimeZone Offset specified in dateTime string (if any).
            // Funny thing is that calling DateTime.Parse(dateTime) would automatically modify DateTime for its value in a system timezone.
            tmpDateTime = DateTimeOffset.Parse(dateTime).DateTime;
        }

        catch (Exception) { }
    }

    try
    {
        var tmzID = GetTmzIdByLocation(latitude, longitude);

        DateTimeOffset result;
        if (String.IsNullOrEmpty(tmzID) || tmzID.ToLower() == "uninhabited")   // TimeZone is unknown, it's probably an ocean, so we would just return time offest based on Lat/Long. 
        {
            var offset = GetRoughDateTimeOffsetByLocation(latitude, longitude);
            result = new DateTimeOffset(tmpDateTime, TimeSpan.FromMinutes(offset * 60));  // This only works correctly if tmpDateTime.Kind = Unspecified, see http://goo.gl/at3Vba
        }                                                                      // A known TimeZone is found, we can adjust for DST using Noda Time calls below.
        else
        {
            tzFound = true;
            // This was provided by Jon Skeet
            var localDateTime = LocalDateTime.FromDateTime(tmpDateTime); // See Noda Time docs at http://goo.gl/XseiSa
            var dateTimeZone = DateTimeZoneProviders.Tzdb[tmzID];
            var zonedDateTime = localDateTime.InZoneLeniently(dateTimeZone);  // See Noda Time docs at http://goo.gl/AqE8Qo
            result = zonedDateTime.ToDateTimeOffset(); // BCL DateTimeOffset
            isDST = zonedDateTime.IsDaylightSavingsTime();
        }

        return new { result = result.ToString(IncidentDateFormat), tzFound, isDST };
    }
    catch (Exception ex)
    {
        IMAPLog.LogEvent(System.Reflection.MethodBase.GetCurrentMethod().Name, "", ex);
        throw new CustomHttpException("Unable to get timezone offset.");
    }
}

确定 DST 是否处于活动状态的扩展方法(由 Matt Johnson 提供)What is the System.TimeZoneInfo.IsDaylightSavingTime equivalent in NodaTime?

public static class NodaTimeUtil
{
    // An extension method by Matt Johnson - on Stack Overflow at http://goo.gl/ymy7Wb
    public static bool IsDaylightSavingsTime(this ZonedDateTime zonedDateTime)
    {
        var instant = zonedDateTime.ToInstant();
        var zoneInterval = zonedDateTime.Zone.GetZoneInterval(instant);
        return zoneInterval.Savings != Offset.Zero;
    }
}

【讨论】:

    猜你喜欢
    • 2014-03-03
    • 2013-07-12
    • 2016-12-04
    • 2019-01-31
    • 2011-08-04
    • 1970-01-01
    • 2011-03-22
    • 2016-09-05
    • 1970-01-01
    相关资源
    最近更新 更多