X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mcs%2Fclass%2FSystem.Core%2FSystem%2FTimeZoneInfo.cs;h=aead18c764f230a9889dc542459b921994681f3a;hb=4320e844e92386319c01095435e6ae0c67bfc09a;hp=bb670c84a673fcf0ada8c8022cef1c60ad5d3dce;hpb=486ee8d8f47912dec4bb0f24cdc9752b25bf07a7;p=mono.git diff --git a/mcs/class/System.Core/System/TimeZoneInfo.cs b/mcs/class/System.Core/System/TimeZoneInfo.cs index bb670c84a67..aead18c764f 100644 --- a/mcs/class/System.Core/System/TimeZoneInfo.cs +++ b/mcs/class/System.Core/System/TimeZoneInfo.cs @@ -1,3 +1,4 @@ + /* * System.TimeZoneInfo * @@ -28,12 +29,13 @@ using System; using System.Runtime.CompilerServices; +using System.Threading; -#if !INSIDE_CORLIB && (NET_4_0 || MOBILE) +#if !INSIDE_CORLIB && NET_4_0 [assembly:TypeForwardedTo (typeof(TimeZoneInfo))] -#elif (INSIDE_CORLIB && (NET_4_0 || MOBILE)) || (!INSIDE_CORLIB && (NET_3_5 && !NET_4_0 && !MOBILE)) +#elif (INSIDE_CORLIB && NET_4_0) || (!INSIDE_CORLIB && (NET_3_5 && !NET_4_0 && !MOBILE)) using System.Collections.Generic; using System.Collections.ObjectModel; @@ -84,37 +86,48 @@ namespace System static TimeZoneInfo local; public static TimeZoneInfo Local { get { - if (local == null) { + var l = local; + if (l == null) { + l = CreateLocal (); + if (l == null) + throw new TimeZoneNotFoundException (); + + if (Interlocked.CompareExchange (ref local, l, null) != null) + l = local; + } + + return l; + } + } + + static TimeZoneInfo CreateLocal () + { #if MONODROID - local = ZoneInfoDB.Default; + return AndroidTimeZones.Default; #elif MONOTOUCH - using (Stream stream = GetMonoTouchDefault ()) { - local = BuildFromStream ("Local", stream); - } + using (Stream stream = GetMonoTouchData (null)) { + return BuildFromStream ("Local", stream); + } #elif LIBC - try { - local = FindSystemTimeZoneByFileName ("Local", "/etc/localtime"); - } catch { - try { - local = FindSystemTimeZoneByFileName ("Local", Path.Combine (TimeZoneDirectory, "localtime")); - } catch { - throw new TimeZoneNotFoundException (); - } - } -#else - if (IsWindows && LocalZoneKey != null) { - string name = (string)LocalZoneKey.GetValue ("TimeZoneKeyName"); - name = TrimSpecial (name); - if (name != null) - local = TimeZoneInfo.FindSystemTimeZoneById (name); - } - - if (local == null) - throw new TimeZoneNotFoundException (); -#endif + try { + return FindSystemTimeZoneByFileName ("Local", "/etc/localtime"); + } catch { + try { + return FindSystemTimeZoneByFileName ("Local", Path.Combine (TimeZoneDirectory, "localtime")); + } catch { + return null; } - return local; } +#else + if (IsWindows && LocalZoneKey != null) { + string name = (string)LocalZoneKey.GetValue ("TimeZoneKeyName"); + name = TrimSpecial (name); + if (name != null) + return TimeZoneInfo.FindSystemTimeZoneById (name); + } + + return null; +#endif } string standardDisplayName; @@ -214,36 +227,38 @@ namespace System public static DateTime ConvertTime (DateTime dateTime, TimeZoneInfo destinationTimeZone) { - return ConvertTime (dateTime, TimeZoneInfo.Local, destinationTimeZone); + return ConvertTime (dateTime, dateTime.Kind == DateTimeKind.Utc ? TimeZoneInfo.Utc : TimeZoneInfo.Local, destinationTimeZone); } public static DateTime ConvertTime (DateTime dateTime, TimeZoneInfo sourceTimeZone, TimeZoneInfo destinationTimeZone) { + if (sourceTimeZone == null) + throw new ArgumentNullException ("sourceTimeZone"); + + if (destinationTimeZone == null) + throw new ArgumentNullException ("destinationTimeZone"); + if (dateTime.Kind == DateTimeKind.Local && sourceTimeZone != TimeZoneInfo.Local) throw new ArgumentException ("Kind property of dateTime is Local but the sourceTimeZone does not equal TimeZoneInfo.Local"); if (dateTime.Kind == DateTimeKind.Utc && sourceTimeZone != TimeZoneInfo.Utc) throw new ArgumentException ("Kind property of dateTime is Utc but the sourceTimeZone does not equal TimeZoneInfo.Utc"); - + if (sourceTimeZone.IsInvalidTime (dateTime)) throw new ArgumentException ("dateTime parameter is an invalid time"); - if (sourceTimeZone == null) - throw new ArgumentNullException ("sourceTimeZone"); - - if (destinationTimeZone == null) - throw new ArgumentNullException ("destinationTimeZone"); - if (dateTime.Kind == DateTimeKind.Local && sourceTimeZone == TimeZoneInfo.Local && destinationTimeZone == TimeZoneInfo.Local) return dateTime; DateTime utc = ConvertTimeToUtc (dateTime); - if (destinationTimeZone == TimeZoneInfo.Utc) - return utc; - - return ConvertTimeFromUtc (utc, destinationTimeZone); - + if (destinationTimeZone != TimeZoneInfo.Utc) { + utc = ConvertTimeFromUtc (utc, destinationTimeZone); + if (dateTime.Kind == DateTimeKind.Unspecified) + return DateTime.SpecifyKind (utc, DateTimeKind.Unspecified); + } + + return utc; } public static DateTimeOffset ConvertTime(DateTimeOffset dateTimeOffset, TimeZoneInfo destinationTimeZone) @@ -285,13 +300,19 @@ namespace System if (this == TimeZoneInfo.Utc) return DateTime.SpecifyKind (dateTime, DateTimeKind.Utc); - + //FIXME: do not rely on DateTime implementation ! - if (this == TimeZoneInfo.Local) + if (this == TimeZoneInfo.Local) + { +#if NET_4_0 + return dateTime.ToLocalTime (); +#else return DateTime.SpecifyKind (dateTime.ToLocalTime (), DateTimeKind.Unspecified); +#endif + } + AdjustmentRule rule = GetApplicableRule (dateTime); - if (rule != null && IsDaylightSavingTime (DateTime.SpecifyKind (dateTime, DateTimeKind.Utc))) return DateTime.SpecifyKind (dateTime + BaseUtcOffset + rule.DaylightDelta , DateTimeKind.Unspecified); else @@ -394,7 +415,7 @@ namespace System } #endif #if MONODROID - var timeZoneInfo = ZoneInfoDB.GetTimeZone (id); + var timeZoneInfo = AndroidTimeZones.GetTimeZone (id); if (timeZoneInfo == null) throw new TimeZoneNotFoundException (); return timeZoneInfo; @@ -551,11 +572,6 @@ namespace System } #endif - public static TimeZoneInfo FromSerializedString (string source) - { - throw new NotImplementedException (); - } - public AdjustmentRule [] GetAdjustmentRules () { if (!supportsDaylightSavingTime) @@ -598,7 +614,15 @@ namespace System public void GetObjectData (SerializationInfo info, StreamingContext context) #endif { - throw new NotImplementedException (); + if (info == null) + throw new ArgumentNullException ("info"); + info.AddValue ("Id", id); + info.AddValue ("DisplayName", displayName); + info.AddValue ("StandardName", standardDisplayName); + info.AddValue ("DaylightName", daylightDisplayName); + info.AddValue ("BaseUtcOffset", baseUtcOffset); + info.AddValue ("AdjustmentRules", adjustmentRules); + info.AddValue ("SupportsDaylightSavingTime", SupportsDaylightSavingTime); } //FIXME: change this to a generic Dictionary and allow caching for FindSystemTimeZoneById @@ -619,15 +643,17 @@ namespace System } #endif #if MONODROID - foreach (string id in ZoneInfoDB.GetAvailableIds ()) { - var tz = ZoneInfoDB.GetTimeZone (id); + foreach (string id in AndroidTimeZones.GetAvailableIds ()) { + var tz = AndroidTimeZones.GetTimeZone (id); if (tz != null) systemTimeZones.Add (tz); } #elif MONOTOUCH if (systemTimeZones.Count == 0) { foreach (string name in GetMonoTouchNames ()) { - using (Stream stream = GetMonoTouchData (name)) { + using (Stream stream = GetMonoTouchData (name, false)) { + if (stream == null) + continue; systemTimeZones.Add (BuildFromStream (name, stream)); } } @@ -726,6 +752,18 @@ namespace System throw new NotImplementedException (); } + bool IsInDSTForYear (AdjustmentRule rule, DateTime dateTime, int year) + { + DateTime DST_start = TransitionPoint (rule.DaylightTransitionStart, year); + DateTime DST_end = TransitionPoint (rule.DaylightTransitionEnd, year + ((rule.DaylightTransitionStart.Month < rule.DaylightTransitionEnd.Month) ? 0 : 1)); + if (dateTime.Kind == DateTimeKind.Utc) { + DST_start -= BaseUtcOffset; + DST_end -= (BaseUtcOffset + rule.DaylightDelta); + } + + return (dateTime >= DST_start && dateTime < DST_end); + } + public bool IsDaylightSavingTime (DateTime dateTime) { if (dateTime.Kind == DateTimeKind.Local && IsInvalidTime (dateTime)) @@ -733,29 +771,28 @@ namespace System if (this == TimeZoneInfo.Utc) return false; - + if (!SupportsDaylightSavingTime) return false; + //FIXME: do not rely on DateTime implementation ! if ((dateTime.Kind == DateTimeKind.Local || dateTime.Kind == DateTimeKind.Unspecified) && this == TimeZoneInfo.Local) return dateTime.IsDaylightSavingTime (); - + //FIXME: do not rely on DateTime implementation ! if (dateTime.Kind == DateTimeKind.Local && this != TimeZoneInfo.Utc) return IsDaylightSavingTime (DateTime.SpecifyKind (dateTime.ToUniversalTime (), DateTimeKind.Utc)); - + AdjustmentRule rule = GetApplicableRule (dateTime.Date); if (rule == null) return false; - DateTime DST_start = TransitionPoint (rule.DaylightTransitionStart, dateTime.Year); - DateTime DST_end = TransitionPoint (rule.DaylightTransitionEnd, dateTime.Year + ((rule.DaylightTransitionStart.Month < rule.DaylightTransitionEnd.Month) ? 0 : 1)); - if (dateTime.Kind == DateTimeKind.Utc) { - DST_start -= BaseUtcOffset; - DST_end -= (BaseUtcOffset + rule.DaylightDelta); - } + // Check whether we're in the dateTime year's DST period + if (IsInDSTForYear (rule, dateTime, dateTime.Year)) + return true; - return (dateTime >= DST_start && dateTime < DST_end); + // We might be in the dateTime previous year's DST period + return IsInDSTForYear (rule, dateTime, dateTime.Year - 1); } public bool IsDaylightSavingTime (DateTimeOffset dateTimeOffset) @@ -786,17 +823,72 @@ namespace System public void OnDeserialization (object sender) #endif { - throw new NotImplementedException (); + try { + TimeZoneInfo.Validate (id, baseUtcOffset, adjustmentRules); + } catch (ArgumentException ex) { + throw new SerializationException ("invalid serialization data", ex); + } + } + + private static void Validate (string id, TimeSpan baseUtcOffset, AdjustmentRule [] adjustmentRules) + { + if (id == null) + throw new ArgumentNullException ("id"); + + if (id == String.Empty) + throw new ArgumentException ("id parameter is an empty string"); + + if (baseUtcOffset.Ticks % TimeSpan.TicksPerMinute != 0) + throw new ArgumentException ("baseUtcOffset parameter does not represent a whole number of minutes"); + + if (baseUtcOffset > new TimeSpan (14, 0, 0) || baseUtcOffset < new TimeSpan (-14, 0, 0)) + throw new ArgumentOutOfRangeException ("baseUtcOffset parameter is greater than 14 hours or less than -14 hours"); + +#if STRICT + if (id.Length > 32) + throw new ArgumentException ("id parameter shouldn't be longer than 32 characters"); +#endif + + if (adjustmentRules != null && adjustmentRules.Length != 0) { + AdjustmentRule prev = null; + foreach (AdjustmentRule current in adjustmentRules) { + if (current == null) + throw new InvalidTimeZoneException ("one or more elements in adjustmentRules are null"); + + if ((baseUtcOffset + current.DaylightDelta < new TimeSpan (-14, 0, 0)) || + (baseUtcOffset + current.DaylightDelta > new TimeSpan (14, 0, 0))) + throw new InvalidTimeZoneException ("Sum of baseUtcOffset and DaylightDelta of one or more object in adjustmentRules array is greater than 14 or less than -14 hours;"); + + if (prev != null && prev.DateStart > current.DateStart) + throw new InvalidTimeZoneException ("adjustment rules specified in adjustmentRules parameter are not in chronological order"); + + if (prev != null && prev.DateEnd > current.DateStart) + throw new InvalidTimeZoneException ("some adjustment rules in the adjustmentRules parameter overlap"); + + if (prev != null && prev.DateEnd == current.DateStart) + throw new InvalidTimeZoneException ("a date can have multiple adjustment rules applied to it"); + + prev = current; + } + } } - public string ToSerializedString () + public override string ToString () { - throw new NotImplementedException (); + return DisplayName; } - public override string ToString () + private TimeZoneInfo (SerializationInfo info, StreamingContext context) { - return DisplayName; + if (info == null) + throw new ArgumentNullException ("info"); + id = (string) info.GetValue ("Id", typeof (string)); + displayName = (string) info.GetValue ("DisplayName", typeof (string)); + standardDisplayName = (string) info.GetValue ("StandardName", typeof (string)); + daylightDisplayName = (string) info.GetValue ("DaylightName", typeof (string)); + baseUtcOffset = (TimeSpan) info.GetValue ("BaseUtcOffset", typeof (TimeSpan)); + adjustmentRules = (TimeZoneInfo.AdjustmentRule []) info.GetValue ("AdjustmentRules", typeof (TimeZoneInfo.AdjustmentRule [])); + supportsDaylightSavingTime = (bool) info.GetValue ("SupportsDaylightSavingTime", typeof (bool)); } private TimeZoneInfo (string id, TimeSpan baseUtcOffset, string displayName, string standardDisplayName, string daylightDisplayName, TimeZoneInfo.AdjustmentRule [] adjustmentRules, bool disableDaylightSavingTime) @@ -886,6 +978,8 @@ namespace System int day = 1 + (transition.Week - 1) * 7 + (transition.DayOfWeek - first) % 7; if (day > DateTime.DaysInMonth (year, transition.Month)) day -= 7; + if (day < 1) + day += 7; return new DateTime (year, transition.Month, day) + transition.TimeOfDay.TimeOfDay; }