在NodaTime中获得夏令时开始和结束时间

如何使用Noda Time获取夏令时的开始和结束日期? 下面的function完成了这个任务,但它非常笨拙,并且正在寻求一个更简单的解决方案。

///  /// Gets the start and end of daylight savings time in a given time zone ///  /// The time zone in question /// A tuple indicating the start and end of DST /// Assumes this zone has daylight savings time private Tuple GetZoneStartAndEnd(DateTimeZone tz) { int thisYear = TimeUtils.SystemLocalDateTime.Year; // Get the year of the current LocalDateTime // Get January 1, midnight, of this year and next year. var yearStart = new LocalDateTime(thisYear, 1, 1, 0, 0).InZoneLeniently(tz).ToInstant(); var yearEnd = new LocalDateTime(thisYear + 1, 1, 1, 0, 0).InZoneLeniently(tz).ToInstant(); // Get the intervals that we experience in this year var intervals = tz.GetZoneIntervals(yearStart, yearEnd).ToArray(); // Assuming we are in a US-like daylight savings scheme, // we should see three intervals: // 1. The interval that January 1st sits in // 2. At some point, daylight savings will start. // 3. At some point, daylight savings will stop. if (intervals.Length == 1) throw new Exception("This time zone does not use daylight savings time"); if (intervals.Length != 3) throw new Exception("The daylight savings scheme in this time zone is unexpected."); return new Tuple(intervals[1].IsoLocalStart, intervals[1].IsoLocalEnd); } 

我所知道的没有一个内置函数,但数据就在那里,所以你当然可以自己创建。

您已经在正确的轨道上展示了您所展示的内容,但有几点需要考虑:

  • 通常人们对间隔的终点感兴趣。 通过仅返回中间间隔的开始和停止,您可能获得的值与您预期的不同。 例如,如果您使用其中一个美国时区,例如"America/Los_Angeles" ,则您的函数将返回过渡时间为3/9/2014 3:00:00 AM11/2/2014 2:00:00 AM ,你可能希望两者都是凌晨2点。

  • 赤道以南使用夏令时的时区将在年底开始,并在明年年初结束。 因此,有时元组中的项可能会与您期望的相反。

  • 有很多时区不使用夏令时,所以抛出exception不是最好的主意。

  • 目前至少有两个时区在一年内有四个过渡期( "Africa/Casablanca""Africa/Cairo" ) – 在斋月的DST期间有一个“rest”。 偶尔也有非DST相关的转换,例如萨摩亚在2011年改变其标准偏移量 ,这使其在一年内实现了三次转换。

考虑到所有这些因素,返回单个转换点列表似乎更好,而不是返回转换对的元组。

此外,这是次要的,但最好不要将方法绑定到系统时钟。 年份可以通过参数轻松传递。 然后,如有必要,您可以将此方法用于非当前年份。

 public IEnumerable GetDaylightSavingTransitions(DateTimeZone timeZone, int year) { var yearStart = new LocalDateTime(year, 1, 1, 0, 0).InZoneLeniently(timeZone).ToInstant(); var yearEnd = new LocalDateTime(year + 1, 1, 1, 0, 0).InZoneLeniently(timeZone).ToInstant(); var intervals = timeZone.GetZoneIntervals(yearStart, yearEnd); return intervals.Select(x => x.IsoLocalEnd).Where(x => x.Year == year); } 

另请注意,最后,仅过滤当前年份的值非常重要,因为间隔可能会很好地延伸到下一年,或者无限期地继续。