The Labs \ Source Viewer \ SSCLI \ System \ TimeZone

  1. // ==++==
  2. //
  3. //
  4. // Copyright (c) 2006 Microsoft Corporation. All rights reserved.
  5. //
  6. // The use and distribution terms for this software are contained in the file
  7. // named license.txt, which can be found in the root of this distribution.
  8. // By using this software in any fashion, you are agreeing to be bound by the
  9. // terms of this license.
  10. //
  11. // You must not remove this notice, or any other, from this software.
  12. //
  13. //
  14. // ==--==
  15. /*============================================================
  16. **
  17. ** Class: TimeZone
  18. **
  19. **
  20. ** Purpose:
  21. ** This class is used to represent a TimeZone.  It
  22. ** has methods for converting a DateTime to UTC from local time
  23. ** and to local time from UTC and methods for getting the
  24. ** standard name and daylight name of the time zone. 
  25. **
  26. ** The only TimeZone that we support in version 1 is the
  27. ** CurrentTimeZone as determined by the system timezone.
  28. **
  29. **
  30. ============================================================*/
  31. namespace System
  32. {
  33.     using System;
  34.     using System.Text;
  35.     using System.Threading;
  36.     using System.Collections;
  37.     using System.Globalization;
  38.    
  39.     [Serializable()]
  40.     [System.Runtime.InteropServices.ComVisible(true)]
  41.     public abstract class TimeZone
  42.     {
  43.         private static TimeZone currentTimeZone = null;
  44.        
  45.         // Private object for locking instead of locking on a public type for SQL reliability work.
  46.         private static object s_InternalSyncObject;
  47.         private static object InternalSyncObject {
  48.             get {
  49.                 if (s_InternalSyncObject == null) {
  50.                     object o = new object();
  51.                     Interlocked.CompareExchange(ref s_InternalSyncObject, o, null);
  52.                 }
  53.                 return s_InternalSyncObject;
  54.             }
  55.         }
  56.        
  57.        
  58.         protected TimeZone()
  59.         {
  60.         }
  61.        
  62.         public static TimeZone CurrentTimeZone {
  63.             get {
  64.                 //Grabbing the cached value is required at the top of this function so that
  65.                 //we don't incur a race condition with the ResetTimeZone method below.
  66.                 TimeZone tz = currentTimeZone;
  67.                 if (tz == null) {
  68.                     lock (InternalSyncObject) {
  69.                         if (currentTimeZone == null) {
  70.                             currentTimeZone = new CurrentSystemTimeZone();
  71.                         }
  72.                         tz = currentTimeZone;
  73.                     }
  74.                 }
  75.                 return (tz);
  76.             }
  77.         }
  78.        
  79.         //This method is called by CultureInfo.ClearCachedData in response to control panel
  80.         //change events. It must be synchronized because otherwise there is a race condition
  81.         //with the CurrentTimeZone property above.
  82.         static internal void ResetTimeZone()
  83.         {
  84.             if (currentTimeZone != null) {
  85.                 lock (InternalSyncObject) {
  86.                     currentTimeZone = null;
  87.                 }
  88.             }
  89.         }
  90.        
  91.         public abstract string StandardName {
  92.             get;
  93.         }
  94.        
  95.         public abstract string DaylightName {
  96.             get;
  97.         }
  98.        
  99.         public abstract TimeSpan GetUtcOffset(DateTime time);
  100.        
  101.         //
  102.         // Converts the specified datatime to the Universal time base on the current timezone
  103.         //
  104.         public virtual DateTime ToUniversalTime(DateTime time)
  105.         {
  106.             if (time.Kind == DateTimeKind.Utc) {
  107.                 return time;
  108.             }
  109.             long tickCount = time.Ticks - GetUtcOffset(time).Ticks;
  110.             if (tickCount > DateTime.MaxTicks) {
  111.                 return new DateTime(DateTime.MaxTicks, DateTimeKind.Utc);
  112.             }
  113.             if (tickCount < DateTime.MinTicks) {
  114.                 return new DateTime(DateTime.MinTicks, DateTimeKind.Utc);
  115.             }
  116.             return new DateTime(tickCount, DateTimeKind.Utc);
  117.         }
  118.        
  119.         //
  120.         // Convert the specified datetime value from UTC to the local time based on the time zone.
  121.         //
  122.         public virtual DateTime ToLocalTime(DateTime time)
  123.         {
  124.             if (time.Kind == DateTimeKind.Local) {
  125.                 return time;
  126.             }
  127.             bool isAmbiguousLocalDst = false;
  128.             Int64 offset = ((CurrentSystemTimeZone)(TimeZone.CurrentTimeZone)).GetUtcOffsetFromUniversalTime(time, ref isAmbiguousLocalDst);
  129.             return new DateTime(time.Ticks + offset, DateTimeKind.Local, isAmbiguousLocalDst);
  130.         }
  131.        
  132.         // Return an array of DaylightTime which reflects the daylight saving periods in a particular year.
  133.         // We currently only support having one DaylightSavingTime per year.
  134.         // If daylight saving time is not used in this timezone, null will be returned.
  135.         public abstract DaylightTime GetDaylightChanges(int year);
  136.        
  137.         public virtual bool IsDaylightSavingTime(DateTime time)
  138.         {
  139.             return (IsDaylightSavingTime(time, GetDaylightChanges(time.Year)));
  140.         }
  141.        
  142.         // Check if the specified time is in a daylight saving time. Allows the user to
  143.         // specify the array of Daylight Saving Times.
  144.         public static bool IsDaylightSavingTime(DateTime time, DaylightTime daylightTimes)
  145.         {
  146.             return CalculateUtcOffset(time, daylightTimes) != TimeSpan.Zero;
  147.         }
  148.        
  149.         //
  150.         //
  151.         //
  152.        
  153.         //
  154.         //
  155.         //
  156.         //
  157.         //
  158.         static internal TimeSpan CalculateUtcOffset(DateTime time, DaylightTime daylightTimes)
  159.         {
  160.             if (daylightTimes == null) {
  161.                 return TimeSpan.Zero;
  162.             }
  163.             DateTimeKind kind = time.Kind;
  164.             if (kind == DateTimeKind.Utc) {
  165.                 return TimeSpan.Zero;
  166.             }
  167.            
  168.             DateTime startTime;
  169.             DateTime endTime;
  170.            
  171.             // startTime and endTime represent the period from either the start of DST to the end and includes the
  172.             // potentially overlapped times
  173.             startTime = daylightTimes.Start + daylightTimes.Delta;
  174.             endTime = daylightTimes.End;
  175.            
  176.             // For normal time zones, the ambiguous hour is the last hour of daylight saving when you wind the
  177.             // clock back. It is theoretically possible to have a positive delta, (which would really be daylight
  178.             // reduction time), where you would have to wind the clock back in the begnning.
  179.             DateTime ambiguousStart;
  180.             DateTime ambiguousEnd;
  181.             if (daylightTimes.Delta.Ticks > 0) {
  182.                 ambiguousStart = endTime - daylightTimes.Delta;
  183.                 ambiguousEnd = endTime;
  184.             }
  185.             else {
  186.                 ambiguousStart = startTime;
  187.                 ambiguousEnd = startTime - daylightTimes.Delta;
  188.             }
  189.            
  190.             bool isDst = false;
  191.             if (startTime > endTime) {
  192.                 // In southern hemisphere, the daylight saving time starts later in the year, and ends in the beginning of next year.
  193.                 // Note, the summer in the southern hemisphere begins late in the year.
  194.                 if (time >= startTime || time < endTime) {
  195.                     isDst = true;
  196.                 }
  197.             }
  198.             else if (time >= startTime && time < endTime) {
  199.                 // In northern hemisphere, the daylight saving time starts in the middle of the year.
  200.                 isDst = true;
  201.             }
  202.            
  203.             // If this date was previously converted from a UTC date and we were able to detect that the local
  204.             // DateTime would be ambiguous, this data is stored in the DateTime to resolve this ambiguity.
  205.             if (isDst && time >= ambiguousStart && time < ambiguousEnd) {
  206.                 isDst = time.IsAmbiguousDaylightSavingTime();
  207.             }
  208.            
  209.             if (isDst) {
  210.                 return daylightTimes.Delta;
  211.             }
  212.             return TimeSpan.Zero;
  213.         }
  214.     }
  215. }

Developer Fusion