Using the public DaylightTime instead of the internal one in corefx dir for Linux...
authorJose Perez Rodriguez <joperezr@microsoft.com>
Fri, 19 Aug 2016 20:30:25 +0000 (13:30 -0700)
committerJose Perez Rodriguez <joperezr@microsoft.com>
Fri, 19 Aug 2016 20:30:25 +0000 (13:30 -0700)
[tfs-changeset: 1623319]

src/mscorlib/mscorlib.shared.sources.props
src/mscorlib/src/System/CurrentTimeZone.cs [new file with mode: 0644]
src/mscorlib/src/System/TimeZone.cs [new file with mode: 0644]

index 8721252..6d82a34 100644 (file)
     <SystemSources Condition="'$(FeatureCoreClr)'=='true'" Include="$(BclSourcesRoot)\System\AppContext\AppContextDefaultValues.CoreClrOverrides.cs" />
     <SystemSources Include="$(BclSourcesRoot)\System\AppContext\AppContextDefaultValues.Defaults.cs" />
     <SystemSources Include="$(BclSourcesRoot)\System\AppContext\AppContextDefaultValues.Defaults.Central.cs" />
+    <SystemSources Include="$(BclSourcesRoot)\System\CurrentTimeZone.cs" />
+    <SystemSources Include="$(BclSourcesRoot)\System\TimeZone.cs" />
     <SystemSources Include="$(BclSourcesRoot)\System\Object.cs" />
     <SystemSources Include="$(BclSourcesRoot)\System\ICloneable.cs" />
     <SystemSources Include="$(BclSourcesRoot)\System\Action.cs" />
     <GlobalizationSources Include="$(BclSourcesRoot)\System\Globalization\NumberStyles.cs" />
     <GlobalizationSources Include="$(BclSourcesRoot)\System\Globalization\TimeSpanFormat.cs" />
     <GlobalizationSources Include="$(BclSourcesRoot)\System\Globalization\TimeSpanParse.cs" />
+    <GlobalizationSources Include="$(BclSourcesRoot)\System\Globalization\DayLightTime.cs" />
   </ItemGroup>
   <ItemGroup Condition="'$(FeatureCoreFxGlobalization)' != 'true'">
     <GlobalizationSources Include="$(BclSourcesRoot)\System\Globalization\BidiCategory.cs" />
     <GlobalizationSources Include="$(BclSourcesRoot)\System\Globalization\CultureTypes.cs" />
     <GlobalizationSources Include="$(BclSourcesRoot)\System\Globalization\DateTimeFormatInfo.cs" />
     <GlobalizationSources Include="$(BclSourcesRoot)\System\Globalization\DateTimeFormatInfoScanner.cs" />
-    <GlobalizationSources Include="$(BclSourcesRoot)\System\Globalization\DaylightTime.cs" />
     <GlobalizationSources Include="$(BclSourcesRoot)\System\Globalization\DigitShapes.cs" />
     <GlobalizationSources Include="$(BclSourcesRoot)\System\Globalization\EncodingDataItem.cs" />
     <GlobalizationSources Include="$(BclSourcesRoot)\System\Globalization\EncodingTable.cs" />
     <GlobalizationSources Include="$(CoreFxSourcesRoot)\System\Globalization\CultureNotFoundException.cs" />
     <GlobalizationSources Include="$(CoreFxSourcesRoot)\System\Globalization\DateTimeFormatInfo.cs" />
     <GlobalizationSources Include="$(CoreFxSourcesRoot)\System\Globalization\DateTimeFormatInfoScanner.cs" />
-    <GlobalizationSources Include="$(CoreFxSourcesRoot)\System\Globalization\DayLightTime.cs" />
     <GlobalizationSources Include="$(CoreFxSourcesRoot)\System\Globalization\EastAsianLunisolarCalendar.cs" />
     <GlobalizationSources Include="$(CoreFxSourcesRoot)\System\Globalization\GregorianCalendar.cs" />
     <GlobalizationSources Include="$(CoreFxSourcesRoot)\System\Globalization\GregorianCalendarHelper.cs" />
diff --git a/src/mscorlib/src/System/CurrentTimeZone.cs b/src/mscorlib/src/System/CurrentTimeZone.cs
new file mode 100644 (file)
index 0000000..f015c05
--- /dev/null
@@ -0,0 +1,310 @@
+// 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.
+
+/*============================================================
+**
+** Class: CurrentTimeZone
+**
+**
+** 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.
+**
+**
+============================================================*/
+namespace System {
+    using System;
+    using System.Diagnostics.Contracts;
+    using System.Text;
+    using System.Threading;
+    using System.Collections;
+    using System.Globalization;
+    using System.Runtime.CompilerServices;
+    using System.Runtime.Versioning;
+
+    //
+    // Currently, this is the only supported timezone.
+    // The values of the timezone is from the current system timezone setting in the
+    // control panel.
+    //
+#if FEATURE_CORECLR
+    [Obsolete("System.CurrentSystemTimeZone has been deprecated.  Please investigate the use of System.TimeZoneInfo.Local instead.")]
+#endif
+    [Serializable]
+    internal class CurrentSystemTimeZone : TimeZone {
+        // <BUGBUG>BUGBUG :
+        // One problem is when user changes the current timezone.  We 
+        // are not able to update currentStandardName/currentDaylightName/
+        // currentDaylightChanges.
+        // We need WM_TIMECHANGE to do this or use
+        // RegNotifyChangeKeyValue() to monitor </BUGBUG>
+        //    
+        private const long TicksPerMillisecond = 10000;
+        private const long TicksPerSecond = TicksPerMillisecond * 1000;
+        private const long TicksPerMinute = TicksPerSecond * 60;
+
+        // The per-year information is cached in in this instance value. As a result it can
+        // be cleaned up by CultureInfo.ClearCachedData, which will clear the instance of this object
+        private Hashtable m_CachedDaylightChanges = new Hashtable();
+
+        // 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;
+             
+        [System.Security.SecuritySafeCritical]  // auto-generated
+        internal CurrentSystemTimeZone() {
+            m_ticksOffset = nativeGetTimeZoneMinuteOffset() * TicksPerMinute;
+            m_standardName = null;
+            m_daylightName = null;
+        }
+    
+        public override String StandardName {
+            [System.Security.SecuritySafeCritical]  // auto-generated
+            get {
+                if (m_standardName == null) {
+                    m_standardName = nativeGetStandardName();
+                }
+                return (m_standardName);
+            }    
+        }
+
+        public override String DaylightName {
+            [System.Security.SecuritySafeCritical]  // auto-generated
+            get {
+                if (m_daylightName == null) {
+                    m_daylightName = nativeGetDaylightName(); 
+                    if (m_daylightName == null) {
+                        m_daylightName = this.StandardName;
+                    }
+                }
+                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);            
+        }
+
+        // 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;
+            }
+        }
+
+
+        [System.Security.SecuritySafeCritical]  // auto-generated
+        public override DaylightTime GetDaylightChanges(int year) {
+            if (year < 1 || year > 9999) {
+                throw new ArgumentOutOfRangeException("year", Environment.GetResourceString("ArgumentOutOfRange_Range", 1, 9999));
+            }
+            Contract.EndContractBlock();
+
+            Object objYear = (Object)year;
+
+            if (!m_CachedDaylightChanges.Contains(objYear)) {
+                lock (InternalSyncObject) {
+
+                    if (!m_CachedDaylightChanges.Contains(objYear)) {
+
+                        //
+                        // rawData is an array of 17 short (16 bit) numbers.
+                        // The first 8 numbers contains the 
+                        // year/month/day/dayOfWeek/hour/minute/second/millisecond for the starting time of daylight saving time.
+                        // The next 8 numbers contains the
+                        // year/month/day/dayOfWeek/hour/minute/second/millisecond for the ending time of daylight saving time.
+                        // The last short number is the delta to the standard offset in minutes.
+                        //
+                        short[] rawData = nativeGetDaylightChanges(year);
+
+                        if (rawData == null) {
+                            //
+                            // If rawData is null, it means that daylight saving time is not used
+                            // in this timezone. So keep currentDaylightChanges as the empty array.
+                            //
+                            m_CachedDaylightChanges.Add(objYear, new DaylightTime(DateTime.MinValue, DateTime.MinValue, TimeSpan.Zero));
+                        } else {
+                            DateTime start;
+                            DateTime end;
+                            TimeSpan delta;
+
+                            //
+                            // Store the start of daylight saving time.
+                            //
+
+                            start = GetDayOfWeek(year, (rawData[0] != 0), rawData[1], rawData[2],
+                                                  rawData[3],
+                                                  rawData[4], rawData[5], rawData[6], rawData[7]);
+
+                            //
+                            // Store the end of daylight saving time.
+                            //
+                            end = GetDayOfWeek(year, (rawData[8] != 0), rawData[9], rawData[10],
+                                                rawData[11],
+                                                rawData[12], rawData[13], rawData[14], rawData[15]);
+
+                            delta = new TimeSpan(rawData[16] * TicksPerMinute);
+                            DaylightTime currentDaylightChanges = new DaylightTime(start, end, delta);
+                            m_CachedDaylightChanges.Add(objYear, currentDaylightChanges);
+                        }
+                    }
+                }
+            }        
+
+            DaylightTime result = (DaylightTime)m_CachedDaylightChanges[objYear];
+
+            return result;
+        }
+
+        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);                    
+            }
+        }
+
+        //
+        // Return the (numberOfSunday)th day of week in a particular year/month.
+        //
+        private static DateTime GetDayOfWeek(int year, bool fixedDate, int month, int targetDayOfWeek, int numberOfSunday, int hour, int minute, int second, int millisecond) {
+            DateTime time;
+            
+            if (fixedDate) {
+                //
+                // Create a Fixed-Date transition time based on the supplied parameters
+                // For Fixed-Dated transition times, the 'numberOfSunday' parameter actually
+                // represents the day of the month.
+                //
+
+                // if the day is out of range for the month then use the last day of the month
+                int day = DateTime.DaysInMonth(year, month);
+
+                time = new DateTime(year, month, (day < numberOfSunday) ? day : numberOfSunday,
+                                  hour, minute, second, millisecond, DateTimeKind.Local);
+            }
+            else if (numberOfSunday <= 4) {
+                //
+                // Get the (numberOfSunday)th Sunday.
+                //
+                
+                time = new DateTime(year, month, 1, hour, minute, second, millisecond, DateTimeKind.Local);
+    
+                int dayOfWeek = (int)time.DayOfWeek;
+                int delta = targetDayOfWeek - dayOfWeek;
+                if (delta < 0) {
+                    delta += 7;
+                }
+                delta += 7 * (numberOfSunday - 1);
+    
+                if (delta > 0) {
+                    time = time.AddDays(delta);
+                }
+            } else {
+                //
+                // If numberOfSunday is greater than 4, we will get the last sunday.
+                //
+                Calendar cal = GregorianCalendar.GetDefaultInstance();            
+                time = new DateTime(year, month, cal.GetDaysInMonth(year, month), hour, minute, second, millisecond, DateTimeKind.Local);
+                // This is the day of week for the last day of the month.
+                int dayOfWeek = (int)time.DayOfWeek;
+                int delta = dayOfWeek - targetDayOfWeek;
+                if (delta < 0) {
+                    delta += 7;
+                }
+                
+                if (delta > 0) {
+                    time = time.AddDays(-delta);
+                }
+            }
+            return (time);
+        }
+
+        [System.Security.SecurityCritical]  // auto-generated
+        [MethodImplAttribute(MethodImplOptions.InternalCall)]
+        internal extern static int nativeGetTimeZoneMinuteOffset();
+        [System.Security.SecurityCritical]  // auto-generated
+        [MethodImplAttribute(MethodImplOptions.InternalCall)]
+        internal extern static String nativeGetDaylightName();
+        [System.Security.SecurityCritical]  // auto-generated
+        [MethodImplAttribute(MethodImplOptions.InternalCall)]
+        internal extern static String nativeGetStandardName();
+        [System.Security.SecurityCritical]  // auto-generated
+        [MethodImplAttribute(MethodImplOptions.InternalCall)]
+        internal extern static short[] nativeGetDaylightChanges(int year);
+    } // class CurrentSystemTimeZone
+}
diff --git a/src/mscorlib/src/System/TimeZone.cs b/src/mscorlib/src/System/TimeZone.cs
new file mode 100644 (file)
index 0000000..602e86a
--- /dev/null
@@ -0,0 +1,249 @@
+// 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.
+
+/*============================================================
+**
+** 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.
+**
+**
+============================================================*/
+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;
+        }
+    }
+}