【问题标题】:Getting Daylight Savings Time Start and End in NodaTime在 NodaTime 中获取夏令时的开始和结束
【发布时间】:2014-08-13 22:44:20
【问题描述】:

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

/// <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);
}

【问题讨论】:

    标签: c# date dst nodatime


    【解决方案1】:

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

    您所展示的内容是正确的,但有几点需要考虑:

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

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

    • 有相当多的时区不使用夏令时,因此抛出异常并不是最好的办法。

    • 目前至少有两个时区在一年中有四个转换("Africa/Casablanca""Africa/Cairo") - 在斋月的 DST 期间有一个“休息”。偶尔也会出现与 DST 无关的转换,例如 Samoa changed its standard offset in 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);
    }
    

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

    【讨论】:

    • 这将是简单 bool IsDaylightSavings(DateTimeZone timeZone, Instant instant) 方法的正确基础,还是有更好的方法?
    • 你的方法是做什么的? Noda Time 的文档不容易理解。我不明白 IsoLocalEnd 是什么以及如何使用它来获取 DST 转换时间。
    • @Azimuth - 根据文档,ZoneInterval “表示适用特定偏移量的时间范围,” 及其 IsoLocalEnd 属性 ”返回间隔的本地开始时间,如 ISO 日历中的 LocalDateTime。这不包括任何夏令时"。这些是半开区间,因此这为我们提供了转换发生的本地时间。
    • 例如,在美国,我们刚刚进行了回退过渡,我们通常说“在当地时间 2:00,回到当地时间 1:00”。实际上,它是“时钟接近 2:00”。如果您实际上是 2:00,则转换已经提前一个小时发生。但当我们要求过渡时,仍然是我们感兴趣的 2:00 时间。因此,我们需要区域间隔的IsoLocalEnd 值。
    • 我在没有节点时间的情况下解决了我的问题。不幸的是,他们的文档远不能理解......
    【解决方案2】:

    这个 sn-p 代码还可以帮助您检查时间是否处于夏令时

    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();
    

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

    【讨论】:

    • ".InZone(timezone)" 似乎无法编译。 ZonedDateTime timeInZone = dateTimeOffset.DateTime.InZone(timezone);
    • 你需要使用 NodaTime;
    猜你喜欢
    • 2020-08-16
    • 2011-03-10
    • 2015-05-03
    • 1970-01-01
    • 2015-11-23
    • 2019-04-25
    • 2023-03-04
    • 2019-06-16
    • 1970-01-01
    相关资源
    最近更新 更多