[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