我试图在一个时间间隔中看到时区中看到的所有偏移量。以下是我用来完成此功能的功能,我知道您可以在标准时间内使用TimeZoneInfo.BaseUtcOffset
获取时区的UTC offset
,但在夏令时期间没有类似的方法来获取时区,除非您将特定的DST
时间点传递给GetUTCOffset()
方法。
static void GetOffsets(DateTime startTime, DateTime endTime, TimeZoneInfo tz)
{
var result = new HashSet<int>();
var adjRules = tz.GetAdjustmentRules();
result.Add(tz.BaseUtcOffset);
foreach (var adjustmentRule in adjRules)
{
if ((startTime >= adjustmentRule.DateStart && startTime <= adjustmentRule.DateEnd) || (endTime >= adjustmentRule.DateStart && endTime <= adjustmentRule.DateEnd) ||
(stTime <= adjustmentRule.DateStart && endTime >= adjustmentRule.DateEnd))
{
if(adjustmentRule.DaylightDelta != TimeSpan.Zero)
{
if (!result.Contains(tz.BaseUtcOffset + adjustmentRule.DaylightDelta))
result.Add((tz.BaseUtcOffset + adjustmentRule.DaylightDelta));
}
}
}
foreach (var res in result)
{
Console.WriteLine(res);
}
}
如果有更好的方法,请告诉我。
答案 0 :(得分:6)
我试图在一个时间间隔中看到时区中看到的所有偏移量。
我强烈建议您避免直接使用TimeZoneInfo
。对于某些区域而言,调整规则在某些年份可能会令人惊讶地尴尬,因为我发现了我的费用。
虽然我有偏见,但我建议使用Noda Time,TimeZoneInfo
可以包裹BclDateTimeZone.FromTimeZoneInfo
并通过public IEnumerable<ZoneInterval> GetZoneIntervalsInInterval
(this DateTimeZone zone, Interval interval)
{
Instant current = interval.Start;
while (current < interval.End && current != Instant.MaxValue)
{
ZoneInterval zi = zone.GetZoneInterval(current);
yield return zi;
current = zi.End;
}
}
为您付出艰苦的努力。您的问题在要求方面并不完全清楚,但如果您可以多说一些您想要做的事情,我可以为您编写适当的Noda Time代码。
您的初步说明可以通过以下方式实施:
var zone = BclDateTimeZone.FromTimeZoneInfo(tzInfo);
var offsets = zone.GetZoneIntervalsInInterval(interval)
.Select(zi => zi.WallOffset)
.Distinct();
然后:
{{1}}
假设你和我一样用“偏移”来表示同样的事情(即UTC和当地时间之间的差异)。
答案 1 :(得分:0)
我确实采用这种方法来获取offSets,需要考虑指定timezoneinfo的一年间隔内的UTC间隔。我将此集合传递给数据库以过滤以UTC格式保存的日期时间字段,用于间隔过滤器输入,如(“上午1点 - 凌晨2点”),我对我系统中的所有时区进行了测试,并且工作正常。虽然这不是我原来问题的答案,因为我仍然使用调整规则来获取offSets,但我这次尝试使其可用。
class Program
{
static void Main(string[] args)
{
foreach (var tz in TimeZoneInfo.GetSystemTimeZones())
{
var result = GetUTCOffsetsByUTCIntervals(1900, 2012, tz);
Console.WriteLine(tz.DisplayName);
foreach (var tuple in result)
{
Console.WriteLine(tuple.Item1 + " " + tuple.Item2 + " " + tuple.Item3);
}
Console.WriteLine("------------------------------------------------------------");
}
Console.Read();
}
public static List<Tuple<TimeSpan, DateTime, DateTime>> GetUTCOffsetsByUTCIntervals(int stYear, int endYear, TimeZoneInfo tz)
{
var cal = CultureInfo.CurrentCulture.Calendar;
var offsetsByUTCIntervals = new List<Tuple<TimeSpan, DateTime, DateTime>>();
var adjRules = tz.GetAdjustmentRules();
for (var year = stYear; year <= endYear && year < DateTime.MaxValue.Year && year >= DateTime.MinValue.Year; year++)
{
var adjRule =
adjRules.FirstOrDefault(
rule =>
rule.DateStart.Year == year || rule.DateEnd.Year == year ||
(rule.DateStart.Year < year && rule.DateEnd.Year > year));
var yrStTime = new DateTime(year, 1, 1);
var yrEndTime = yrStTime.AddYears(1).AddTicks(-1);
if (adjRule != null)
{
var tStDate = GetTransitionDate(adjRule.DaylightTransitionStart, year);
var tEnddate = GetTransitionDate(adjRule.DaylightTransitionEnd, year);
var stTsp = adjRule.DaylightTransitionStart.TimeOfDay.TimeOfDay;
var endTsp = adjRule.DaylightTransitionEnd.TimeOfDay.TimeOfDay;
if (yrStTime.Date == tStDate && yrStTime.TimeOfDay == stTsp)
yrStTime = yrStTime.Add(adjRule.DaylightDelta);
if (yrEndTime.Date == tEnddate && yrEndTime.TimeOfDay == endTsp)
yrEndTime = yrEndTime.Subtract(adjRule.DaylightDelta);
if (tStDate.Month > tEnddate.Month)
{
offsetsByUTCIntervals.Add(new Tuple<TimeSpan, DateTime, DateTime>(tz.BaseUtcOffset + adjRule.DaylightDelta, ConvertTimeToUtc(yrStTime, tz), ConvertTimeToUtc(tEnddate.AddTicks(endTsp.Ticks - 1), tz)));
offsetsByUTCIntervals.Add(new Tuple<TimeSpan, DateTime, DateTime>(tz.BaseUtcOffset, ConvertTimeToUtc(tEnddate.Add(endTsp.Subtract(adjRule.DaylightDelta)), tz), ConvertTimeToUtc(tStDate.AddTicks(stTsp.Ticks - 1), tz)));
offsetsByUTCIntervals.Add(new Tuple<TimeSpan, DateTime, DateTime>(tz.BaseUtcOffset + adjRule.DaylightDelta, ConvertTimeToUtc(tStDate.Add(stTsp.Add(adjRule.DaylightDelta)), tz), ConvertTimeToUtc(yrEndTime, tz)));
}
else
{
offsetsByUTCIntervals.Add(new Tuple<TimeSpan, DateTime, DateTime>(tz.BaseUtcOffset, ConvertTimeToUtc(yrStTime, tz), ConvertTimeToUtc(tStDate.AddTicks(stTsp.Ticks - 1), tz)));
offsetsByUTCIntervals.Add(new Tuple<TimeSpan, DateTime, DateTime>(tz.BaseUtcOffset + adjRule.DaylightDelta, ConvertTimeToUtc(tStDate.Add(stTsp.Add(adjRule.DaylightDelta)), tz), ConvertTimeToUtc(tEnddate.AddTicks(endTsp.Ticks - 1), tz)));
offsetsByUTCIntervals.Add(new Tuple<TimeSpan, DateTime, DateTime>(tz.BaseUtcOffset, ConvertTimeToUtc(tEnddate.Add(endTsp.Subtract(adjRule.DaylightDelta)), tz), ConvertTimeToUtc(yrEndTime, tz)));
}
}
else
{
offsetsByUTCIntervals.Add(new Tuple<TimeSpan, DateTime, DateTime>(tz.BaseUtcOffset, ConvertTimeToUtc(yrStTime, tz), ConvertTimeToUtc(yrEndTime, tz)));
}
}
return offsetsByUTCIntervals;
}
public static DateTime ConvertTimeToUtc(DateTime date, TimeZoneInfo timeZone)
{
if (date == null || timeZone == null)
{
return date;
}
DateTime convertedDate = TimeZoneInfo.ConvertTimeToUtc(date, timeZone);
return convertedDate;
}
//copy from msdn http://msdn.microsoft.com/en-us/library/system.timezoneinfo.transitiontime.isfixeddaterule.aspx
private static DateTime GetTransitionDate(TimeZoneInfo.TransitionTime transition, int year)
{
if (transition.IsFixedDateRule)
return new DateTime(year, transition.Month, transition.Day);
int transitionDay;
var cal = CultureInfo.CurrentCulture.Calendar;
var startOfWeek = transition.Week * 7 - 6;
var firstDayOfWeek = (int)cal.GetDayOfWeek(new DateTime(year, transition.Month, 1));
var changeDayOfWeek = (int)transition.DayOfWeek;
if (firstDayOfWeek <= changeDayOfWeek)
transitionDay = startOfWeek + (changeDayOfWeek - firstDayOfWeek);
else
transitionDay = startOfWeek + (7 - firstDayOfWeek + changeDayOfWeek);
if (transitionDay > cal.GetDaysInMonth(year, transition.Month))
transitionDay -= 7;
return new DateTime(year, transition.Month, transitionDay);
}
/* static void GetOffsets(DateTime startTime, DateTime endTime, TimeZoneInfo tz)
{
var result = new HashSet<string>();
var adjRules = tz.GetAdjustmentRules();
result.Add(tz.BaseUtcOffset.ToString());
foreach (var adjustmentRule in adjRules)
{
if ((startTime >= adjustmentRule.DateStart && startTime <= adjustmentRule.DateEnd)
|| (endTime >= adjustmentRule.DateStart && endTime <= adjustmentRule.DateEnd)
|| (startTime <= adjustmentRule.DateStart && endTime >= adjustmentRule.DateEnd))
{
if(adjustmentRule.DaylightDelta != TimeSpan.Zero)
{
if (!result.Contains((tz.BaseUtcOffset + adjustmentRule.DaylightDelta).ToString()))
result.Add((tz.BaseUtcOffset + adjustmentRule.DaylightDelta).ToString());
}
}
}
Console.Write(tz.DisplayName + " ");
foreach (var res in result)
{
Console.Write(res);
}
}*/
}
答案 2 :(得分:-1)
如果你正在做一些复杂的日期,你应该看一下Noda Time(这是Joda Time Java库的一个端口)。它有一个完整的命名空间来处理棘手的时区问题。