diff options
Diffstat (limited to 'src/mscorlib/shared/System/CurrentSystemTimeZone.cs')
-rw-r--r-- | src/mscorlib/shared/System/CurrentSystemTimeZone.cs | 199 |
1 files changed, 199 insertions, 0 deletions
diff --git a/src/mscorlib/shared/System/CurrentSystemTimeZone.cs b/src/mscorlib/shared/System/CurrentSystemTimeZone.cs new file mode 100644 index 0000000000..2d848397a9 --- /dev/null +++ b/src/mscorlib/shared/System/CurrentSystemTimeZone.cs @@ -0,0 +1,199 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/*============================================================ +** +** +** +** Purpose: +** This class represents the current system timezone. It is +** the only meaningful implementation of the TimeZone class +** available in this version. +** +** The only TimeZone that we support in version 1 is the +** CurrentTimeZone as determined by the system timezone. +** +** +============================================================*/ + +using System; +using System.Diagnostics.Contracts; +using System.Text; +using System.Collections; +using System.Globalization; +using System.Runtime.CompilerServices; +using System.Runtime.Versioning; + +namespace System +{ + [Obsolete("System.CurrentSystemTimeZone has been deprecated. Please investigate the use of System.TimeZoneInfo.Local instead.")] + [Serializable] + internal partial class CurrentSystemTimeZone : TimeZone + { + // Standard offset in ticks to the Universal time if + // no daylight saving is in used. + // E.g. the offset for PST (Pacific Standard time) should be -8 * 60 * 60 * 1000 * 10000. + // (1 millisecond = 10000 ticks) + private long m_ticksOffset; + private String m_standardName; + private String m_daylightName; + + internal CurrentSystemTimeZone() + { + TimeZoneInfo local = TimeZoneInfo.Local; + + m_ticksOffset = local.BaseUtcOffset.Ticks; + m_standardName = local.StandardName; + m_daylightName = local.DaylightName; + } + + public override String StandardName + { + get + { + return m_standardName; + } + } + + public override String DaylightName + { + get + { + return m_daylightName; + } + } + + internal long GetUtcOffsetFromUniversalTime(DateTime time, ref Boolean isAmbiguousLocalDst) + { + // Get the daylight changes for the year of the specified time. + TimeSpan offset = new TimeSpan(m_ticksOffset); + DaylightTime daylightTime = GetDaylightChanges(time.Year); + isAmbiguousLocalDst = false; + + if (daylightTime == null || daylightTime.Delta.Ticks == 0) + { + return offset.Ticks; + } + + // The start and end times represent the range of universal times that are in DST for that year. + // Within that there is an ambiguous hour, usually right at the end, but at the beginning in + // the unusual case of a negative daylight savings delta. + DateTime startTime = daylightTime.Start - offset; + DateTime endTime = daylightTime.End - offset - daylightTime.Delta; + DateTime ambiguousStart; + DateTime ambiguousEnd; + + if (daylightTime.Delta.Ticks > 0) + { + ambiguousStart = endTime - daylightTime.Delta; + ambiguousEnd = endTime; + } + else + { + ambiguousStart = startTime; + ambiguousEnd = startTime - daylightTime.Delta; + } + + Boolean isDst = false; + if (startTime > endTime) + { + // In southern hemisphere, the daylight saving time starts later in the year, and ends in the beginning of next year. + // Note, the summer in the southern hemisphere begins late in the year. + isDst = (time < endTime || time >= startTime); + } + else + { + // In northern hemisphere, the daylight saving time starts in the middle of the year. + isDst = (time >= startTime && time < endTime); + } + + if (isDst) + { + offset += daylightTime.Delta; + + // See if the resulting local time becomes ambiguous. This must be captured here or the + // DateTime will not be able to round-trip back to UTC accurately. + if (time >= ambiguousStart && time < ambiguousEnd) + { + isAmbiguousLocalDst = true; + } + } + return offset.Ticks; + } + + public override DateTime ToLocalTime(DateTime time) + { + if (time.Kind == DateTimeKind.Local) + { + return time; + } + Boolean isAmbiguousLocalDst = false; + Int64 offset = GetUtcOffsetFromUniversalTime(time, ref isAmbiguousLocalDst); + long tick = time.Ticks + offset; + if (tick > DateTime.MaxTicks) + { + return new DateTime(DateTime.MaxTicks, DateTimeKind.Local); + } + if (tick < DateTime.MinTicks) + { + return new DateTime(DateTime.MinTicks, DateTimeKind.Local); + } + return new DateTime(tick, DateTimeKind.Local, isAmbiguousLocalDst); + } + + public override DaylightTime GetDaylightChanges(int year) + { + if (year < 1 || year > 9999) + { + throw new ArgumentOutOfRangeException(nameof(year), SR.Format(SR.ArgumentOutOfRange_Range, 1, 9999)); + } + + return GetCachedDaylightChanges(year); + } + + private static DaylightTime CreateDaylightChanges(int year) + { + DaylightTime currentDaylightChanges = null; + + if (TimeZoneInfo.Local.SupportsDaylightSavingTime) + { + DateTime start; + DateTime end; + TimeSpan delta; + + foreach (var rule in TimeZoneInfo.Local.GetAdjustmentRules()) + { + if (rule.DateStart.Year <= year && rule.DateEnd.Year >= year && rule.DaylightDelta != TimeSpan.Zero) + { + start = TimeZoneInfo.TransitionTimeToDateTime(year, rule.DaylightTransitionStart); + end = TimeZoneInfo.TransitionTimeToDateTime(year, rule.DaylightTransitionEnd); + delta = rule.DaylightDelta; + + currentDaylightChanges = new DaylightTime(start, end, delta); + break; + } + } + } + + if (currentDaylightChanges == null) + { + currentDaylightChanges = new DaylightTime(DateTime.MinValue, DateTime.MinValue, TimeSpan.Zero); + } + + return currentDaylightChanges; + } + + public override TimeSpan GetUtcOffset(DateTime time) + { + if (time.Kind == DateTimeKind.Utc) + { + return TimeSpan.Zero; + } + else + { + return new TimeSpan(TimeZone.CalculateUtcOffset(time, GetDaylightChanges(time.Year)).Ticks + m_ticksOffset); + } + } + } // class CurrentSystemTimeZone +} |