1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252
|
// ==++==
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// ==--==
/*============================================================
**
** Class: TimeZone
**
**
** Purpose:
** This class is used to represent a TimeZone. It
** has methods for converting a DateTime to UTC from local time
** and to local time from UTC and methods for getting the
** standard name and daylight name of the time zone.
**
** The only TimeZone that we support in version 1 is the
** CurrentTimeZone as determined by the system timezone.
**
**
============================================================*/
#if !FEATURE_CORECLR
namespace System {
using System;
using System.Text;
using System.Threading;
using System.Collections;
using System.Globalization;
[Serializable]
[System.Runtime.InteropServices.ComVisible(true)]
#if FEATURE_CORECLR
[Obsolete("System.TimeZone has been deprecated. Please investigate the use of System.TimeZoneInfo instead.")]
#endif
public abstract class TimeZone {
private static volatile TimeZone currentTimeZone = null;
// Private object for locking instead of locking on a public type for SQL reliability work.
private static Object s_InternalSyncObject;
private static Object InternalSyncObject {
get {
if (s_InternalSyncObject == null) {
Object o = new Object();
Interlocked.CompareExchange<Object>(ref s_InternalSyncObject, o, null);
}
return s_InternalSyncObject;
}
}
protected TimeZone() {
}
public static TimeZone CurrentTimeZone {
get {
//Grabbing the cached value is required at the top of this function so that
//we don't incur a race condition with the ResetTimeZone method below.
TimeZone tz = currentTimeZone;
if (tz == null) {
lock(InternalSyncObject) {
if (currentTimeZone == null) {
currentTimeZone = new CurrentSystemTimeZone();
}
tz = currentTimeZone;
}
}
return (tz);
}
}
//This method is called by CultureInfo.ClearCachedData in response to control panel
//change events. It must be synchronized because otherwise there is a race condition
//with the CurrentTimeZone property above.
internal static void ResetTimeZone() {
if (currentTimeZone!=null) {
lock(InternalSyncObject) {
currentTimeZone = null;
}
}
}
public abstract String StandardName {
get;
}
public abstract String DaylightName {
get;
}
public abstract TimeSpan GetUtcOffset(DateTime time);
//
// Converts the specified datatime to the Universal time base on the current timezone
//
public virtual DateTime ToUniversalTime(DateTime time) {
if (time.Kind == DateTimeKind.Utc) {
return time;
}
long tickCount = time.Ticks - GetUtcOffset(time).Ticks;
if (tickCount>DateTime.MaxTicks) {
return new DateTime(DateTime.MaxTicks, DateTimeKind.Utc);
}
if (tickCount<DateTime.MinTicks) {
return new DateTime(DateTime.MinTicks, DateTimeKind.Utc);
}
return new DateTime(tickCount, DateTimeKind.Utc);
}
//
// Convert the specified datetime value from UTC to the local time based on the time zone.
//
public virtual DateTime ToLocalTime(DateTime time) {
if (time.Kind == DateTimeKind.Local) {
return time;
}
Boolean isAmbiguousLocalDst = false;
Int64 offset = ((CurrentSystemTimeZone)(TimeZone.CurrentTimeZone)).GetUtcOffsetFromUniversalTime(time, ref isAmbiguousLocalDst);
return new DateTime(time.Ticks + offset, DateTimeKind.Local, isAmbiguousLocalDst);
}
// Return an array of DaylightTime which reflects the daylight saving periods in a particular year.
// We currently only support having one DaylightSavingTime per year.
// If daylight saving time is not used in this timezone, null will be returned.
public abstract DaylightTime GetDaylightChanges(int year);
public virtual bool IsDaylightSavingTime(DateTime time) {
return (IsDaylightSavingTime(time, GetDaylightChanges(time.Year)));
}
// Check if the specified time is in a daylight saving time. Allows the user to
// specify the array of Daylight Saving Times.
public static bool IsDaylightSavingTime(DateTime time, DaylightTime daylightTimes) {
return CalculateUtcOffset(time, daylightTimes)!=TimeSpan.Zero;
}
//
// NOTENOTE: Implementation detail
// In the transition from standard time to daylight saving time,
// if we convert local time to Universal time, we can have the
// following (take PST as an example):
// Local Universal UTC Offset
// ----- --------- ----------
// 01:00AM 09:00 -8:00
// 02:00 (=> 03:00) 10:00 -8:00 [This time doesn't actually exist, but it can be created from DateTime]
// 03:00 10:00 -7:00
// 04:00 11:00 -7:00
// 05:00 12:00 -7:00
//
// So from 02:00 - 02:59:59, we should return the standard offset, instead of the daylight saving offset.
//
// In the transition from daylight saving time to standard time,
// if we convert local time to Universal time, we can have the
// following (take PST as an example):
// Local Universal UTC Offset
// ----- --------- ----------
// 01:00AM 08:00 -7:00
// 02:00 (=> 01:00) 09:00 -8:00
// 02:00 10:00 -8:00
// 03:00 11:00 -8:00
// 04:00 12:00 -8:00
//
// So in this case, the 02:00 does exist after the first 2:00 rolls back to 01:00. We don't need to special case this.
// But note that there are two 01:00 in the local time.
//
// And imagine if the daylight saving offset is negative (although this does not exist in real life)
// In the transition from standard time to daylight saving time,
// if we convert local time to Universal time, we can have the
// following (take PST as an example, but the daylight saving offset is -01:00):
// Local Universal UTC Offset
// ----- --------- ----------
// 01:00AM 09:00 -8:00
// 02:00 (=> 01:00) 10:00 -9:00
// 02:00 11:00 -9:00
// 03:00 12:00 -9:00
// 04:00 13:00 -9:00
// 05:00 14:00 -9:00
//
// So in this case, the 02:00 does exist after the first 2:00 rolls back to 01:00. We don't need to special case this.
//
// In the transition from daylight saving time to standard time,
// if we convert local time to Universal time, we can have the
// following (take PST as an example, daylight saving offset is -01:00):
//
// Local Universal UTC Offset
// ----- --------- ----------
// 01:00AM 10:00 -9:00
// 02:00 (=> 03:00) 11:00 -9:00
// 03:00 11:00 -8:00
// 04:00 12:00 -8:00
// 05:00 13:00 -8:00
// 06:00 14:00 -8:00
//
// So from 02:00 - 02:59:59, we should return the daylight saving offset, instead of the standard offset.
//
internal static TimeSpan CalculateUtcOffset(DateTime time, DaylightTime daylightTimes) {
if (daylightTimes==null) {
return TimeSpan.Zero;
}
DateTimeKind kind = time.Kind;
if (kind == DateTimeKind.Utc) {
return TimeSpan.Zero;
}
DateTime startTime;
DateTime endTime;
// startTime and endTime represent the period from either the start of DST to the end and includes the
// potentially overlapped times
startTime = daylightTimes.Start + daylightTimes.Delta;
endTime = daylightTimes.End;
// For normal time zones, the ambiguous hour is the last hour of daylight saving when you wind the
// clock back. It is theoretically possible to have a positive delta, (which would really be daylight
// reduction time), where you would have to wind the clock back in the begnning.
DateTime ambiguousStart;
DateTime ambiguousEnd;
if (daylightTimes.Delta.Ticks > 0) {
ambiguousStart = endTime - daylightTimes.Delta;
ambiguousEnd = endTime;
} else {
ambiguousStart = startTime;
ambiguousEnd = startTime - daylightTimes.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.
if (time >= startTime || time < endTime) {
isDst = true;
}
}
else if (time>=startTime && time < endTime) {
// In northern hemisphere, the daylight saving time starts in the middle of the year.
isDst = true;
}
// If this date was previously converted from a UTC date and we were able to detect that the local
// DateTime would be ambiguous, this data is stored in the DateTime to resolve this ambiguity.
if (isDst && time >= ambiguousStart && time < ambiguousEnd) {
isDst = time.IsAmbiguousDaylightSavingTime();
}
if (isDst) {
return daylightTimes.Delta;
}
return TimeSpan.Zero;
}
}
}
#endif // FEATURE_CORECLR
|