Fix IDE0025 (use expression body for properties)
[mono-project.git] / netcore / System.Private.CoreLib / shared / System / CurrentSystemTimeZone.cs
blob2df633396a6cacb464af3c31a77a8f4f51c00e87
1 // Licensed to the .NET Foundation under one or more agreements.
2 // The .NET Foundation licenses this file to you under the MIT license.
3 // See the LICENSE file in the project root for more information.
5 /*============================================================
6 **
7 **
8 **
9 ** Purpose:
10 ** This class represents the current system timezone. It is
11 ** the only meaningful implementation of the TimeZone class
12 ** available in this version.
14 ** The only TimeZone that we support in version 1 is the
15 ** CurrentTimeZone as determined by the system timezone.
18 ============================================================*/
20 using System.Collections;
21 using System.Globalization;
23 namespace System
25 [Obsolete("System.CurrentSystemTimeZone has been deprecated. Please investigate the use of System.TimeZoneInfo.Local instead.")]
26 internal class CurrentSystemTimeZone : TimeZone
28 // Standard offset in ticks to the Universal time if
29 // no daylight saving is in used.
30 // E.g. the offset for PST (Pacific Standard time) should be -8 * 60 * 60 * 1000 * 10000.
31 // (1 millisecond = 10000 ticks)
32 private readonly long m_ticksOffset;
33 private readonly string m_standardName;
34 private readonly string m_daylightName;
36 internal CurrentSystemTimeZone()
38 TimeZoneInfo local = TimeZoneInfo.Local;
40 m_ticksOffset = local.BaseUtcOffset.Ticks;
41 m_standardName = local.StandardName;
42 m_daylightName = local.DaylightName;
45 public override string StandardName => m_standardName;
47 public override string DaylightName => m_daylightName;
49 internal long GetUtcOffsetFromUniversalTime(DateTime time, ref bool isAmbiguousLocalDst)
51 // Get the daylight changes for the year of the specified time.
52 TimeSpan offset = new TimeSpan(m_ticksOffset);
53 DaylightTime daylightTime = GetDaylightChanges(time.Year);
54 isAmbiguousLocalDst = false;
56 if (daylightTime == null || daylightTime.Delta.Ticks == 0)
58 return offset.Ticks;
61 // The start and end times represent the range of universal times that are in DST for that year.
62 // Within that there is an ambiguous hour, usually right at the end, but at the beginning in
63 // the unusual case of a negative daylight savings delta.
64 DateTime startTime = daylightTime.Start - offset;
65 DateTime endTime = daylightTime.End - offset - daylightTime.Delta;
66 DateTime ambiguousStart;
67 DateTime ambiguousEnd;
69 if (daylightTime.Delta.Ticks > 0)
71 ambiguousStart = endTime - daylightTime.Delta;
72 ambiguousEnd = endTime;
74 else
76 ambiguousStart = startTime;
77 ambiguousEnd = startTime - daylightTime.Delta;
80 bool isDst;
81 if (startTime > endTime)
83 // In southern hemisphere, the daylight saving time starts later in the year, and ends in the beginning of next year.
84 // Note, the summer in the southern hemisphere begins late in the year.
85 isDst = (time < endTime || time >= startTime);
87 else
89 // In northern hemisphere, the daylight saving time starts in the middle of the year.
90 isDst = (time >= startTime && time < endTime);
93 if (isDst)
95 offset += daylightTime.Delta;
97 // See if the resulting local time becomes ambiguous. This must be captured here or the
98 // DateTime will not be able to round-trip back to UTC accurately.
99 if (time >= ambiguousStart && time < ambiguousEnd)
101 isAmbiguousLocalDst = true;
104 return offset.Ticks;
107 public override DateTime ToLocalTime(DateTime time)
109 if (time.Kind == DateTimeKind.Local)
111 return time;
113 bool isAmbiguousLocalDst = false;
114 long offset = GetUtcOffsetFromUniversalTime(time, ref isAmbiguousLocalDst);
115 long tick = time.Ticks + offset;
116 if (tick > DateTime.MaxTicks)
118 return new DateTime(DateTime.MaxTicks, DateTimeKind.Local);
120 if (tick < DateTime.MinTicks)
122 return new DateTime(DateTime.MinTicks, DateTimeKind.Local);
124 return new DateTime(tick, DateTimeKind.Local, isAmbiguousLocalDst);
127 public override DaylightTime GetDaylightChanges(int year)
129 if (year < 1 || year > 9999)
131 throw new ArgumentOutOfRangeException(nameof(year), SR.Format(SR.ArgumentOutOfRange_Range, 1, 9999));
134 return GetCachedDaylightChanges(year);
137 private static DaylightTime CreateDaylightChanges(int year)
139 DaylightTime? currentDaylightChanges = null;
141 if (TimeZoneInfo.Local.SupportsDaylightSavingTime)
143 DateTime start;
144 DateTime end;
145 TimeSpan delta;
147 foreach (TimeZoneInfo.AdjustmentRule rule in TimeZoneInfo.Local.GetAdjustmentRules())
149 if (rule.DateStart.Year <= year && rule.DateEnd.Year >= year && rule.DaylightDelta != TimeSpan.Zero)
151 start = TimeZoneInfo.TransitionTimeToDateTime(year, rule.DaylightTransitionStart);
152 end = TimeZoneInfo.TransitionTimeToDateTime(year, rule.DaylightTransitionEnd);
153 delta = rule.DaylightDelta;
155 currentDaylightChanges = new DaylightTime(start, end, delta);
156 break;
161 if (currentDaylightChanges == null)
163 currentDaylightChanges = new DaylightTime(DateTime.MinValue, DateTime.MinValue, TimeSpan.Zero);
166 return currentDaylightChanges;
169 public override TimeSpan GetUtcOffset(DateTime time)
171 if (time.Kind == DateTimeKind.Utc)
173 return TimeSpan.Zero;
175 else
177 return new TimeSpan(TimeZone.CalculateUtcOffset(time, GetDaylightChanges(time.Year)).Ticks + m_ticksOffset);
181 private DaylightTime GetCachedDaylightChanges(int year)
183 object objYear = (object)year;
185 if (!m_CachedDaylightChanges.Contains(objYear))
187 DaylightTime currentDaylightChanges = CreateDaylightChanges(year);
188 lock (m_CachedDaylightChanges)
190 if (!m_CachedDaylightChanges.Contains(objYear))
192 m_CachedDaylightChanges.Add(objYear, currentDaylightChanges);
197 return (DaylightTime)m_CachedDaylightChanges[objYear]!;
200 // The per-year information is cached in this instance value. As a result it can
201 // be cleaned up by CultureInfo.ClearCachedData, which will clear the instance of this object
202 private readonly Hashtable m_CachedDaylightChanges = new Hashtable();
204 } // class CurrentSystemTimeZone