有没有办法找出 C# 夏令时前后的时间范围?

Posted

技术标签:

【中文标题】有没有办法找出 C# 夏令时前后的时间范围?【英文标题】:Is there any way to find out the range of time before and after daylight savings in C#? 【发布时间】:2021-01-26 18:01:31 【问题描述】:

TimeZoneInfo 类中有很多可用的选项来找出当前服务器时间的 UTC 偏移量,如果时间是夏令时等等。

但是有没有办法找出给定日期范围内的夏令时范围

所以基本上说考虑夏令时的任何服务器在一年中的时区偏移是否是

Mar-Oct - UTC-4
Nov-Feb - UCT-5

如果我将范围传递为Jan-Jun,那么我正在寻找的输出就是这个

Jan-Feb   - UTC-5
Mar-Jun   - UTC-4

我已经检查了以下方法和属性以尝试制作,但无法以最佳方式获得所需的输出

TimeZoneInfo.Local.BaseUtcOffset.Hours

TimeZoneInfo.Local.IsDaylightSavingTime

【问题讨论】:

UTC-4 不是时区,而是偏移量。您可以使用TimeZoneInfo.GetAdjustmentRules 获取时区规则 @PanagiotisKanavos - 已更正 不,错误仍然存​​在。您无法获得任何偏移的白天规则,因为没有任何规则。没有 UTC-4 时区。有复活节欧洲、太平洋或印度时区,其偏移量会根据时区甚至国家/地区的规则从例如UTC-4 更改为UTC-5 TimeZoneInfo.AdjustmentRule 的文档示例打印了机器上注册的所有 TimeZoneInfo 对象的所有规则。这包括实际时区和固定偏移量,如UTC-4。 Windows上的TZ信息有点....杂乱无章 @PanagiotisKanavos - 是的,但是夏令时会改变同一个县或地区的时区或偏移量,所以基本上我们在不同时间对同一地区有两个不同的偏移量,不是吗? 【参考方案1】:

我建议使用Noda Time 来解决这个问题。 (当然,您可以使用TimeZoneInfo,但处理调整规则很麻烦。)

声明这些导入:

using System;
using System.Linq;
using NodaTime;

定义一个函数来完成主要工作:

static (LocalDateTime StartDateTime, LocalDateTime UntilDateTime, Offset UtcOffset)[] 
    GetOffsetRanges(DateTimeZone tz, LocalDate startDate, LocalDate untilDate)

    // Get ZonedDateTime values representing the start of day of each date in the given time zone.
    ZonedDateTime startZonedDateTime = startDate.AtStartOfDayInZone(tz);
    ZonedDateTime untilZonedDateTime = untilDate.AtStartOfDayInZone(tz);

    // We'll also need the corresponding Instant of each value.
    Instant startInstant = startZonedDateTime.ToInstant();
    Instant untilInstant = untilZonedDateTime.ToInstant();

    // Get the ZoneInterval values, which tell us the range that an offset is in effect.
    return tz.GetZoneIntervals(startInstant, untilInstant).Select(interval =>
    
        // Snap the values to the range we're working with.  (This is optional, you could just use the IsoLocalStart/End values directly.)
        LocalDateTime startDateTime = interval.Start >= startInstant ? interval.IsoLocalStart : startZonedDateTime.LocalDateTime;
        LocalDateTime untilDateTime = interval.End <= untilInstant ? interval.IsoLocalEnd : untilZonedDateTime.LocalDateTime;

        // Include the local date and time range, and the offset that's in effect over that range.
        return (startDateTime, untilDateTime, interval.WallOffset);

    ).ToArray();

像这样使用函数:

// Define your input values
DateTimeZone tz = DateTimeZoneProviders.Tzdb["America/New_York"];
var startDate = new LocalDate(2020, 1, 1);
var untilDate = new LocalDate(2021, 1, 1);

// Call the function to get the ranges
var ranges = GetOffsetRanges(tz, startDate, untilDate);

// Example output
Console.WriteLine($"Offsets in tz.Id between startDate:R and untilDate:R are as follows:");
foreach (var range in ranges)

    Console.WriteLine($"range.StartDateTime:s - range.UntilDateTime:s : range.UtcOffset:m");

输出:

Offsets in America/New_York between 2020-01-01 and 2021-01-01 are as follows:
2020-01-01T00:00:00 - 2020-03-08T02:00:00 : -05:00
2020-03-08T03:00:00 - 2020-11-01T02:00:00 : -04:00
2020-11-01T01:00:00 - 2021-01-01T00:00:00 : -05:00

几点说明:

我不建议按照您在问题中所述的方式简化输入或输出。说Mar-Oct不够准确。

正如 Panagiotis 在问题 cmets 中指出的那样,您需要确定要使用的时区。单个偏移输入是不够的。我的示例显示了一个命名的 IANA 时区,但如果需要,您可以使用 DateTimeZoneProviders.Tzdb.GetSystemDefault() 来传递系统的本地时区

如果这要在服务器上运行,那么请不要使用系统的本地时区。一般来说,服务器的时区应该被视为无关

在 Web 应用程序中,您可以使用 Intl.DateTimeFormat().resolvedOptions().timeZonejavascript 中获取用户的 IANA 时区标识符。您可以将其传递给您的服务器并将其用作上述代码的输入。 (这适用于大多数现代网络浏览器,但不适用于所有较旧的浏览器。)

【讨论】:

以上是关于有没有办法找出 C# 夏令时前后的时间范围?的主要内容,如果未能解决你的问题,请参考以下文章

有没有办法检查它是不是是 UTC 的 DST(夏令时)?

如果日期是进行 DST(夏令时)更改的实际日期,有没有办法在 Python 中推断?

在两个NSDate之间获得准确的时间差?

使用 Python 找出当前是不是处于夏令时的时区 [重复]

夏令时前后将 Duration.ofDays(1) 和 Period.ofDays(1) 添加到 ZonedDateTime 之间的区别

C# 在时间转换中处理夏令时