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

本文关键字:结束 NodaTime 开始 夏令时 | 更新日期: 2023-09-27 18:09:55

如何使用野田时间获得夏令时的开始和结束日期?下面的函数完成了这个任务,但是它非常笨拙,需要一个更简单的解决方案。

/// <summary>
/// Gets the start and end of daylight savings time in a given time zone
/// </summary>
/// <param name="tz">The time zone in question</param>
/// <returns>A tuple indicating the start and end of DST</returns>
/// <remarks>Assumes this zone has daylight savings time</remarks>
private Tuple<LocalDateTime, LocalDateTime> 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<LocalDateTime,LocalDateTime>(intervals[1].IsoLocalStart, intervals[1].IsoLocalEnd);
}

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

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

你所展示的是正确的,但是有一些事情需要考虑:

  • 通常人们对区间的结束点感兴趣。通过只返回中间间隔的开始和停止,您可能会得到与预期不同的值。例如,如果您使用美国时区之一,例如"America/Los_Angeles",则函数返回转换为3/9/2014 3:00:00 AM11/2/2014 2:00:00 AM,您可能期望两者都是凌晨2:00。

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

  • 有相当多的时区不使用夏令时,所以抛出一个异常并不是最好的主意。

  • 目前至少有两个时区在一年中有四次转换("Africa/Casablanca""Africa/Cairo") -在斋月期间有一个"休息"。偶尔也会出现与dst无关的过渡,例如萨摩亚在2011年改变了其标准偏移量,这使其在一年内三次过渡。

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

同样,这是次要的,但是最好不要将方法绑定到系统时钟。年份可以很容易地通过参数传递。然后,如果有必要,您可以对非当前年度使用此方法。

public IEnumerable<LocalDateTime> 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);
}

最后还要注意,只过滤当年的值是很重要的,因为这些间隔很可能延伸到下一年,或者无限期地持续下去。

这段代码还可以帮助您检查时间是否为daylightsavingstime

public static bool IsDaylightSavingsTime(this DateTimeOffset dateTimeOffset)
        {
            var timezone = "Europe/London"; //https://nodatime.org/TimeZones
            ZonedDateTime timeInZone = dateTimeOffset.DateTime.InZone(timezone);
            var instant = timeInZone.ToInstant();
            var zoneInterval = timeInZone.Zone.GetZoneInterval(instant);
            return zoneInterval.Savings != Offset.Zero;
        }

如何使用

var testDate = DateTimeOffset.Now;
var isDst = testDate.IsDaylightSavingsTime();

根据你的情况,你可以稍微修改一下