有没有办法找出 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().timeZone
在 javascript 中获取用户的 IANA 时区标识符。您可以将其传递给您的服务器并将其用作上述代码的输入。 (这适用于大多数现代网络浏览器,但不适用于所有较旧的浏览器。)
【讨论】:
以上是关于有没有办法找出 C# 夏令时前后的时间范围?的主要内容,如果未能解决你的问题,请参考以下文章
如果日期是进行 DST(夏令时)更改的实际日期,有没有办法在 Python 中推断?
使用 Python 找出当前是不是处于夏令时的时区 [重复]
夏令时前后将 Duration.ofDays(1) 和 Period.ofDays(1) 添加到 ZonedDateTime 之间的区别