首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >NodaTime ZoneIntervals

NodaTime ZoneIntervals
EN

Stack Overflow用户
提问于 2016-05-19 16:10:28
回答 1查看 326关注 0票数 0

我试图构建一个逻辑的时区记录集,表示一个5年的时间,其中停止和开始日期/时间与人们所认为的时间变化时刻夏时制相匹配。例如,在美国/纽约id中,我希望:

代码语言:javascript
复制
03/13/2016 2:00 am    -   11/06/2016  01:59:59 am  gmtOffset:  -4:00
11/06/2016 2:00 am    -   03/12/2017  01:59:59 am  gmtOffset:  -5:00

我能够建立这些记录,但我没有别的办法,只有在1912年dst生效之前开始,并跟踪所有区域间隔的结束时间。我不认为有一种方法可以在间隔记录周期开始时确定偏移量,而不是以前的间隔记录。是否有一种方法只使用一个ZoneInterval记录就可以做到这一点?

守则中指出的问题:

代码语言:javascript
复制
    private void processTZ()
    {
        IDateTimeZoneProvider provider = DateTimeZoneProviders.Tzdb;

        using (StreamWriter sw = new StreamWriter(@"c:\tzOut.txt"))
        {
            foreach (string id in provider.Ids)
            {
                sw.WriteLine("Id: {0}", id);
                DateTimeZone zone = provider[id];

                // Time period I wish to create logical representation.
                Instant instantValidityBegin = (new LocalDateTime(2014, 1, 1, 0, 0)).InZoneLeniently(zone).ToInstant();
                Instant instantValidityEnd = (new LocalDateTime(2019, 12, 31, 23, 59, 59, 0)).InZoneLeniently(zone).ToInstant();

                // Time period from zone intervals to iterate. The first year dst was observed was 1916.
                Instant instantFetchYearBegin = (new LocalDateTime(1916, 1, 1, 0, 0)).InZoneLeniently(zone).ToInstant();
                Instant instantFetchYearEnd = (new LocalDateTime(2019, 12, 31, 23, 59, 0)).InZoneLeniently(zone).ToInstant();

                // Get the intervals
                IEnumerable<NodaTime.TimeZones.ZoneInterval> intervals = zone.GetZoneIntervals(instantFetchYearBegin, instantFetchYearEnd);

                // Determine number of intervals for this tzId.
                int count = 0;
                foreach (NodaTime.TimeZones.ZoneInterval zi in intervals)
                    count++;

                bool singleEntry = (1 == count);

                // myStart and myEnd are desired output period
                // capture IsoLocalEnd of an interval to be used as the start date of program output (myStart).  Don't display older than 1900.
                DateTime myStart, myEnd, prevEnd = new DateTime(1900, 1, 1);

                foreach (NodaTime.TimeZones.ZoneInterval zi in intervals)
                {
                    if (singleEntry)
                    {
                        // No question here
                    }
                    else
                    {
                        // skip intervals for this tzId that represent a period beginning after time period I want.
                        if (instantValidityEnd < zi.Start)
                            break;

                        // Skip intervals ending prior to time period I want, but capture the IsoLocalEnd to be used for report output.
                        if (zi.End < instantValidityBegin)
                        {
                            prevEnd = (zi.End == Instant.MinValue) ? prevEnd = new DateTime(1900, 1, 1) : prevEnd = zi.IsoLocalEnd.ToDateTimeUnspecified(); ;
                            continue;
                        }

                        //   ***Question***  Can this myStart value be determined using the current interval record instead of storing the previous interval's IsoLocalEnd??
                        myStart = prevEnd;
                        if (zi.End == Instant.MaxValue)
                            prevEnd = myEnd = new DateTime(9999, 12, 31);
                        else
                        {
                            prevEnd = zi.IsoLocalEnd.ToDateTimeUnspecified();
                            myEnd = prevEnd.Subtract(TimeSpan.FromSeconds(1));  // force period back 1 second for logical representation.
                        }


                        sw.WriteLine("Name: " + zi.Name);
                        sw.WriteLine("Multi Entry: {0}", zi.ToString());
                        sw.WriteLine("myStart: {0:G}   myEnd: {1:G}    gmtOffset: {2:G}", myStart, myEnd, zi.WallOffset.ToTimeSpan());
                        sw.WriteLine();
                    }
                }

                sw.WriteLine("------------------------------------------------------------------");
                sw.WriteLine();
            }
        }
    }
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2016-05-23 03:48:41

在任何给定的ZoneInterval记录上,IsoLocalStartIsoLocalEnd都是相对于该特定间隔的,对两者使用相同的WallOffset值。

如果您想获得实际的本地时间,您可以使用StartEnd实例并将它们转换到特定的时区。

代码语言:javascript
复制
zi.Start.InZone(zone)
zi.End.InZone(zone)

您会发现起始值的LocalDateTimeIsoLocalStart匹配,但结束值不匹配。当观察到瞬间时,它现在被下一个间隔的偏移所覆盖。别忘了这是半开放的间隔。[inclusive-start, exclusive-end)

让我们回到原始请求中的示例:

2016年03月13日2:00 - 11/06/2016 01:59:59 gmtOffset:-4:00 11/06/2016 2:00 - 03/12/2017 01:59:59 gmtOffset:-5:00 gmtOffset:-5:00

它不是那样工作的。三月份,当地时间从1:59:59 am转到3:00:00 am,跳过了一个多小时。所以第一行应该从3:00 am开始,而不是从2:00 am开始。去年11月,当地时间从01:59:59 am转到了1:00:00 am,重复了一个小时。因此,第二行应该从1:00 am而不是2:00 am开始。您的图表似乎试图使本地时间连续--但事实并非如此。

此外,你会发现,按照惯例,许多人认为转换的时间是2:00,而不是1:59:59。把它想象成接近2点。这就是为什么向IsoLocalEnd显示当前间隔的偏移量,您可以将该字段用于此目的。

另外,您可能需要查看如何timeanddate.com显示的内容。他们决定只显示结束值,这可能会使事情变得更清楚一些。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/37328727

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档