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
答案 0 :(得分: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在问题注释中指出的那样,您需要确定要使用的时区。单偏置输入是不够的。我的示例显示了一个命名的IANA时区,但如果需要,您可以使用DateTimeZoneProviders.Tzdb.GetSystemDefault()
如果此操作将在服务器上运行,请不要使用系统的本地时区。通常,应将服务器的时区视为不相关。
在Web应用程序中,您可以使用Intl.DateTimeFormat().resolvedOptions().timeZone
在JavaScript中获取用户的IANA时区标识符。您可以将其传递给服务器,并将其用作上述代码的输入。 (这适用于大多数现代网络浏览器,但不适用于所有较旧的网络浏览器。)