[Mono-dev] Serialization TimeZoneInfo class
Andreas Auerswald
andreas.auerswald at etit.tu-chemnitz.de
Mon Jun 17 07:50:26 UTC 2013
Hi,
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
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.ximian.com/pipermail/mono-devel-list/attachments/20130617/3573f627/attachment-0001.html>
More information about the Mono-devel-list
mailing list