[Mono-dev] Serialization TimeZoneInfo class

Marek Safar marek.safar at gmail.com
Mon Jun 17 10:03:28 UTC 2013


Hello Andreas,

Could you send pull request instead of inline patch ?

Thanks
Marek

I have implemented the serialization of the TimeZoneInfo class. It is
> compatible to the serialization in .Net so cross serialization shouldn't be
> a problem. I hope it will be included in the next releases of Mono.
>
> The patch:
>
> diff --git a/mcs/class/System.Core/System/TimeZoneInfo.AdjustmentRule.cs
> b/mcs/class/System.Core/System/TimeZoneInfo.AdjustmentRule.cs
> index d3c16f4..4c413a8 100644
> --- a/mcs/class/System.Core/System/TimeZoneInfo.AdjustmentRule.cs
> +++ b/mcs/class/System.Core/System/TimeZoneInfo.AdjustmentRule.cs
> @@ -74,6 +74,17 @@ namespace System
>                  return new AdjustmentRule (dateStart, dateEnd,
> daylightDelta, daylightTransitionStart, daylightTransitionEnd);
>              }
>
> +            private AdjustmentRule (SerializationInfo info,
> StreamingContext context)
> +            {
> +                if (info == null)
> +                    throw new ArgumentNullException ("info");
> +                dateStart = (DateTime) info.GetValue ("DateStart", typeof
> (DateTime));
> +                dateEnd = (DateTime) info.GetValue ("DateEnd", typeof
> (DateTime));
> +                daylightDelta = (TimeSpan) info.GetValue
> ("DaylightDelta", typeof (TimeSpan));
> +                daylightTransitionStart = (TimeZoneInfo.TransitionTime)
> info.GetValue ("DaylightTransitionStart", typeof
> (TimeZoneInfo.TransitionTime));
> +                daylightTransitionEnd = (TimeZoneInfo.TransitionTime)
> info.GetValue ("DaylightTransitionEnd", typeof
> (TimeZoneInfo.TransitionTime));
> +            }
> +
>              private AdjustmentRule (
>                  DateTime dateStart,
>                  DateTime dateEnd,
> @@ -130,7 +141,13 @@ namespace System
>              public void GetObjectData (SerializationInfo info,
> StreamingContext context)
>  #endif
>              {
> -                throw new NotImplementedException ();
> +                if (info == null)
> +                    throw new ArgumentNullException ("info");
> +                info.AddValue ("DateStart", DateStart);
> +                info.AddValue ("DateEnd", DateEnd);
> +                info.AddValue ("DaylightDelta", DaylightDelta);
> +                info.AddValue ("DaylightTransitionStart",
> DaylightTransitionStart);
> +                info.AddValue ("DaylightTransitionEnd",
> DaylightTransitionEnd);
>              }
>  #if NET_4_0
>              void IDeserializationCallback.OnDeserialization (object
> sender)
> @@ -138,7 +155,38 @@ namespace System
>              public void OnDeserialization (object sender)
>  #endif
>              {
> -                throw new NotImplementedException ();
> +                try {
> +                    TimeZoneInfo.AdjustmentRule.Validate (dateStart,
> dateEnd, daylightDelta,
> +
> daylightTransitionStart, daylightTransitionEnd);
> +                } catch (ArgumentException ex) {
> +                    throw new SerializationException ("invalid
> serialization data", (Exception) ex);
> +                }
> +            }
> +
> +            private static void Validate (
> +                DateTime dateStart,
> +                DateTime dateEnd,
> +                TimeSpan daylightDelta,
> +                TransitionTime daylightTransitionStart,
> +                TransitionTime daylightTransitionEnd)
> +            {
> +                if (dateStart.Kind != DateTimeKind.Unspecified ||
> dateEnd.Kind != DateTimeKind.Unspecified)
> +                    throw new ArgumentException ("the Kind property of
> dateStart or dateEnd parameter does not equal DateTimeKind.Unspecified");
> +
> +                if (daylightTransitionStart == daylightTransitionEnd)
> +                    throw new ArgumentException ("daylightTransitionStart
> parameter cannot equal daylightTransitionEnd parameter");
> +
> +                if (dateStart.Ticks % TimeSpan.TicksPerDay != 0 ||
> dateEnd.Ticks % TimeSpan.TicksPerDay != 0)
> +                    throw new ArgumentException ("dateStart or dateEnd
> parameter includes a time of day value");
> +
> +                if (dateEnd < dateStart)
> +                    throw new ArgumentOutOfRangeException ("dateEnd is
> earlier than dateStart");
> +
> +                if (daylightDelta > new TimeSpan (14, 0, 0) ||
> daylightDelta < new TimeSpan (-14, 0, 0))
> +                    throw new ArgumentOutOfRangeException ("daylightDelta
> is less than -14 or greater than 14 hours");
> +
> +                if (daylightDelta.Ticks % TimeSpan.TicksPerSecond != 0)
> +                    throw new ArgumentOutOfRangeException ("daylightDelta
> parameter does not represent a whole number of seconds");
>              }
>          }
>      }
> diff --git a/mcs/class/System.Core/System/TimeZoneInfo.TransitionTime.cs
> b/mcs/class/System.Core/System/TimeZoneInfo.TransitionTime.cs
> index a914ed1..0a72ce2 100644
> --- a/mcs/class/System.Core/System/TimeZoneInfo.TransitionTime.cs
> +++ b/mcs/class/System.Core/System/TimeZoneInfo.TransitionTime.cs
> @@ -108,6 +108,26 @@ namespace System
>                  return new TransitionTime (timeOfDay, month, week,
> dayOfWeek);
>              }
>
> +            private TransitionTime (SerializationInfo info,
> StreamingContext context)
> +            {
> +                if (info == null)
> +                    throw new ArgumentNullException ("info");
> +                timeOfDay = (DateTime) info.GetValue ("TimeOfDay", typeof
> (DateTime));
> +                month = (byte) info.GetValue ("Month", typeof (byte));
> +                week = (byte) info.GetValue ("Week", typeof (byte));
> +                day = (byte) info.GetValue ("Day", typeof (byte));
> +                dayOfWeek = (DayOfWeek) info.GetValue ("DayOfWeek",
> typeof (DayOfWeek));
> +                isFixedDateRule = (bool) info.GetValue
> ("IsFixedDateRule", typeof (bool));
> +
> +                if (isFixedDateRule)
> +                {
> +                    week = -1;
> +                    dayOfWeek = (DayOfWeek) (-1);
> +                }
> +                if (!isFixedDateRule)
> +                    day = -1;
> +            }
> +
>              private TransitionTime (
>                  DateTime timeOfDay,
>                  int month,
> @@ -190,9 +210,25 @@ namespace System
>              public void GetObjectData (SerializationInfo info,
> StreamingContext context)
>  #endif
>              {
> -                throw new NotImplementedException ();
> -            }
> -
> +                if (info == null)
> +                    throw new ArgumentNullException ("info");
> +                info.AddValue ("TimeOfDay", TimeOfDay);
> +                info.AddValue ("Month", System.Convert.ToByte(Month));
> +                if (week > -1)
> +                    info.AddValue ("Week", System.Convert.ToByte(week));
> +                else
> +                    info.AddValue ("Week", (byte) 1);
> +                if (day > -1)
> +                    info.AddValue ("Day", System.Convert.ToByte(day));
> +                else
> +                    info.AddValue ("Day", (byte) 1);
> +                if (dayOfWeek !=  ((System.DayOfWeek) (-1)))
> +                    info.AddValue ("DayOfWeek", dayOfWeek);
> +                else
> +                    info.AddValue ("DayOfWeek", DayOfWeek.Sunday);
> +                info.AddValue ("IsFixedDateRule", IsFixedDateRule);
> +            }
> +
>              public override bool Equals (object obj)
>              {
>                  if (obj is TransitionTime)
> @@ -216,7 +252,50 @@ namespace System
>              public void OnDeserialization (object sender)
>  #endif
>              {
> -                throw new NotImplementedException ();
> +                try {
> +                    TimeZoneInfo.TransitionTime.Validate (timeOfDay,
> month, week, day, dayOfWeek, isFixedDateRule);
> +                } catch (ArgumentException ex) {
> +                    throw new SerializationException ("invalid
> serialization data", (Exception) ex);
> +                }
> +            }
> +
> +            private static void Validate (DateTime timeOfDay, int
> month,int week, int day, DayOfWeek dayOfWeek, bool isFixedDateRule)
> +            {
> +                if (timeOfDay.Year != 1 || timeOfDay.Month != 1 ||
> timeOfDay.Day != 1)
> +                    throw new ArgumentException ("timeOfDay parameter has
> a non-default date component");
> +
> +                if (timeOfDay.Kind != DateTimeKind.Unspecified)
> +                    throw new ArgumentException ("timeOfDay parameter
> Kind's property is not DateTimeKind.Unspecified");
> +
> +                if (timeOfDay.Ticks % TimeSpan.TicksPerMillisecond != 0)
> +                    throw new ArgumentException ("timeOfDay parameter
> does not represent a whole number of milliseconds");
> +
> +                if (day < 1 || day > 31)
> +                {
> +                    if (!(!isFixedDateRule && day == -1))
> +                        throw new ArgumentOutOfRangeException ("day
> parameter is less than 1 or greater than 31");
> +                }
> +
> +                if (week < 1 || week > 5)
> +                {
> +                    if (!(isFixedDateRule && week == -1))
> +                        throw new ArgumentOutOfRangeException ("week
> parameter is less than 1 or greater than 5");
> +                }
> +
> +                if (month < 1 || month > 12)
> +                    throw new ArgumentOutOfRangeException ("month
> parameter is less than 1 or greater than 12");
> +
> +                if (dayOfWeek != DayOfWeek.Sunday &&
> +                        dayOfWeek != DayOfWeek.Monday &&
> +                        dayOfWeek != DayOfWeek.Tuesday &&
> +                        dayOfWeek != DayOfWeek.Wednesday &&
> +                        dayOfWeek != DayOfWeek.Thursday &&
> +                        dayOfWeek != DayOfWeek.Friday &&
> +                        dayOfWeek != DayOfWeek.Saturday)
> +                {
> +                    if (!(isFixedDateRule && dayOfWeek == (DayOfWeek)
> (-1)))
> +                        throw new ArgumentOutOfRangeException ("dayOfWeek
> parameter is not a member od DayOfWeek enumeration");
> +                }
>              }
>          }
>      }
> diff --git a/mcs/class/System.Core/System/TimeZoneInfo.cs
> b/mcs/class/System.Core/System/TimeZoneInfo.cs
> index ee440a4..dd3c656 100644
> --- a/mcs/class/System.Core/System/TimeZoneInfo.cs
> +++ b/mcs/class/System.Core/System/TimeZoneInfo.cs
> @@ -598,11 +531,19 @@ 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
> @@ -786,9 +725,56 @@ 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", (Exception) 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 ()
>          {
>              throw new NotImplementedException ();
> @@ -850,10 +832,24 @@ namespace System
>              this.adjustmentRules = adjustmentRules;
>          }
>
> +        private TimeZoneInfo (SerializationInfo info, StreamingContext
> context)
> +        {
> +            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 AdjustmentRule GetApplicableRule (DateTime dateTime)
>          {
>              //Transitions are always in standard time
> diff --git
> a/mcs/class/System.Core/Test/System/TimeZoneInfo.AdjustmentRuleTest.cs
> b/mcs/class/System.Core/Test/System/TimeZoneInfo.AdjustmentRuleTest.cs
> index 6fd2412..e20c37d 100644
> ---
> "a/mcs/class/System.Core/Test/System/TimeZoneInfo.AdjustmentRuleTest.cs"
> +++
> "b/mcs/class/System.Core/Test/System/TimeZoneInfo.AdjustmentRuleTest.cs"
> @@ -1,4 +1,6 @@
>  using System;
> +using System.IO;
> +using System.Runtime.Serialization.Formatters;
>  using NUnit.Framework;
>
>  #if NET_2_0
> @@ -89,7 +91,33 @@ public void DeltaNotInSeconds ()
>                  TimeZoneInfo.TransitionTime daylightTransitionEnd =
> TimeZoneInfo.TransitionTime.CreateFixedDateRule (new DateTime
> (1,1,1,2,0,0), 10, 11);
>                  TimeZoneInfo.AdjustmentRule.CreateAdjustmentRule
> (dateStart, dateEnd, new TimeSpan (55), daylightTransitionStart,
> daylightTransitionEnd);
>              }
> -        }
> +        }
> +
> +       [TestFixture]
> +        public class SerializationTests
> +        {
> +            TimeZoneInfo.AdjustmentRule rule;
> +
> +            [SetUp]
> +            public void CreateRule ()
> +            {
> +                TimeZoneInfo.TransitionTime start =
> TimeZoneInfo.TransitionTime.CreateFloatingDateRule (new DateTime
> (1,1,1,1,0,0), 3, 5, DayOfWeek.Sunday);
> +                TimeZoneInfo.TransitionTime end =
> TimeZoneInfo.TransitionTime.CreateFloatingDateRule (new DateTime
> (1,1,1,2,0,0), 10, 5, DayOfWeek.Sunday);
> +                rule = TimeZoneInfo.AdjustmentRule.CreateAdjustmentRule
> (DateTime.MinValue.Date, DateTime.MaxValue.Date, new TimeSpan (1,0,0),
> start, end);
> +            }
> +
> +            [Test]
> +            public void Serialization_Deserialization ()
> +            {
> +                MemoryStream stream = new MemoryStream ();
> +                BinaryFormatter formatter = new BinaryFormatter ();
> +                formatter.Serialize (stream, rule);
> +                stream.Position = 0;
> +                TimeZoneInfo.AdjustmentRule deserialized =
> (TimeZoneInfo.AdjustmentRule) formatter.Deserialize (stream);
> +                stream.Close ();
> +                stream.Dispose ();
> +                Assert.AreEqual (rule, deserialized);
> +            }
> +        }
>      }
>  }
> #endif
> diff --git
> a/mcs/class/System.Core/Test/System/TimeZoneInfo.TransitionTimeTest.cs
> b/mcs/class/System.Core/Test/System/TimeZoneInfo.TransitionTimeTest.cs
> index 8dd8263..2fd2e70 100644
> ---
> "a/mcs/class/System.Core/Test/System/TimeZoneInfo.TransitionTimeTest.cs"
> +++
> "b/mcs/class/System.Core/Test/System/TimeZoneInfo.TransitionTimeTest.cs"
> @@ -1,5 +1,7 @@
>
>  using System;
> +using System.IO;
> +using System.Runtime.Serialization.Formatters;
>  using NUnit.Framework;
>
>  #if NET_2_0
> @@ -107,6 +109,46 @@ public void EqualsObject ()
>                  Assert.IsFalse (tt1.Equals (tt2), "2!=1");
>              }
>          }
> +
> +       [TestFixture]
> +        public class SerializationTests
> +        {
> +            TimeZoneInfo.TransitionTime floatingDateRule;
> +            TimeZoneInfo.TransitionTime fixedDateRule;
> +
> +            [SetUp]
> +            public void CreateDateRules ()
> +            {
> +                floatingDateRule =
> TimeZoneInfo.TransitionTime.CreateFloatingDateRule(new DateTime(1, 1, 1, 1,
> 0, 0), 3, 5, DayOfWeek.Sunday);
> +                fixedDateRule =
> TimeZoneInfo.TransitionTime.CreateFixedDateRule(new DateTime(1, 1, 1, 1, 0,
> 0), 3, 12);
> +            }
> +
> +            [Test]
> +            public void Serialize_Deserialize_FloatingDateRule ()
> +            {
> +                MemoryStream stream = new MemoryStream ();
> +                BinaryFormatter formatter = new BinaryFormatter ();
> +                formatter.Serialize (stream, floatingDateRule);
> +                stream.Position = 0;
> +                TimeZoneInfo.TransitionTime deserialized =
> (TimeZoneInfo.TransitionTime) formatter.Deserialize (stream);
> +                stream.Close ();
> +                stream.Dispose ();
> +                Assert.AreEqual (floatingDateRule, deserialized);
> +            }
> +
> +            [Test]
> +            public void Serialize_Deserialize_FixedDateRule ()
> +            {
> +                MemoryStream stream = new MemoryStream ();
> +                BinaryFormatter formatter = new BinaryFormatter ();
> +                formatter.Serialize (stream, fixedDateRule);
> +                stream.Position = 0;
> +                TimeZoneInfo.TransitionTime deserialized =
> (TimeZoneInfo.TransitionTime) formatter.Deserialize (stream);
> +                stream.Close ();
> +                stream.Dispose ();
> +                Assert.AreEqual (fixedDateRule, deserialized);
> +            }
> +        }
>      }
>  }
>  #endif
> diff --git a/mcs/class/System.Core/Test/System/TimeZoneInfoTest.cs
> b/mcs/class/System.Core/Test/System/TimeZoneInfoTest.cs
> index 06de33e..f678acf 100644
> --- "a/mcs/class/System.Core/Test/System/TimeZoneInfoTest.cs"
> +++ "b/mcs/class/System.Core/Test/System/TimeZoneInfoTest.cs"
> @@ -28,6 +28,8 @@
>
>  using System;
>  using System.Collections;
> +using System.IO;
> +using System.Runtime.Serialization.Formatters;
>
>  using NUnit.Framework;
>  #if NET_2_0
> @@ -657,6 +659,34 @@ public class HasSameRulesTests
>                  Assert.IsTrue (utc.HasSameRules (custom));
>              }
>          }
> +
> +       [TestFixture]
> +        public class SerializationTests
> +        {
> +            TimeZoneInfo london;
> +
> +            [SetUp]
> +            public void CreateTimeZones ()
> +            {
> +                TimeZoneInfo.TransitionTime start =
> TimeZoneInfo.TransitionTime.CreateFloatingDateRule (new DateTime
> (1,1,1,1,0,0), 3, 5, DayOfWeek.Sunday);
> +                TimeZoneInfo.TransitionTime end =
> TimeZoneInfo.TransitionTime.CreateFloatingDateRule (new DateTime
> (1,1,1,2,0,0), 10, 5, DayOfWeek.Sunday);
> +                TimeZoneInfo.AdjustmentRule rule =
> TimeZoneInfo.AdjustmentRule.CreateAdjustmentRule (DateTime.MinValue.Date,
> DateTime.MaxValue.Date, new TimeSpan (1,0,0), start, end);
> +                london = TimeZoneInfo.CreateCustomTimeZone
> ("Europe/London", new TimeSpan (0), "Europe/London", "British Standard
> Time", "British Summer Time", new TimeZoneInfo.AdjustmentRule [] {rule});
> +            }
> +
> +            [Test]
> +            public void Serialization_Deserialization ()
> +            {
> +                MemoryStream stream = new MemoryStream ();
> +                BinaryFormatter formatter = new BinaryFormatter ();
> +                formatter.Serialize (stream, london);
> +                stream.Position = 0;
> +                TimeZoneInfo deserialized = (TimeZoneInfo)
> formatter.Deserialize (stream);
> +                stream.Close ();
> +                stream.Dispose ();
> +                Assert.AreEqual (london, deserialized);
> +            }
> +        }
>      }
>  }
>  #endif
>
>
> _______________________________________________
> Mono-devel-list mailing list
> Mono-devel-list at lists.ximian.com
> http://lists.ximian.com/mailman/listinfo/mono-devel-list
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.ximian.com/pipermail/mono-devel-list/attachments/20130617/13d340b6/attachment-0001.html>


More information about the Mono-devel-list mailing list