diff --git a/src/ServiceStack.Text/Common/DateTimeSerializer.cs b/src/ServiceStack.Text/Common/DateTimeSerializer.cs index 05cae8b37..fd19170a0 100644 --- a/src/ServiceStack.Text/Common/DateTimeSerializer.cs +++ b/src/ServiceStack.Text/Common/DateTimeSerializer.cs @@ -56,7 +56,7 @@ public static DateTime ParseShortestXsdDateTime(string dateTimeStr) public static string ToDateTimeString(DateTime dateTime) { - return TimeZoneInfo.ConvertTimeToUtc(dateTime).ToString(XsdDateTimeFormat); + return dateTime.ToStableUniversalTime().ToString(XsdDateTimeFormat); } public static DateTime ParseDateTime(string dateTimeStr) @@ -66,7 +66,7 @@ public static DateTime ParseDateTime(string dateTimeStr) public static string ToXsdDateTimeString(DateTime dateTime) { - return XmlConvert.ToString(TimeZoneInfo.ConvertTimeToUtc(dateTime), XmlDateTimeSerializationMode.Utc); + return XmlConvert.ToString(dateTime.ToStableUniversalTime(), XmlDateTimeSerializationMode.Utc); } public static DateTime ParseXsdDateTime(string dateTimeStr) @@ -82,7 +82,7 @@ public static string ToShortestXsdDateTimeString(DateTime dateTime) return dateTime.ToString(ShortDateTimeFormat); if (timeOfDay.Milliseconds == 0) - return TimeZoneInfo.ConvertTimeToUtc(dateTime).ToString(XsdDateTimeFormatSeconds); + return dateTime.ToStableUniversalTime().ToString(XsdDateTimeFormatSeconds); return ToXsdDateTimeString(dateTime); } diff --git a/src/ServiceStack.Text/DateTimeExtensions.cs b/src/ServiceStack.Text/DateTimeExtensions.cs index 3f01db553..9cd41eb97 100644 --- a/src/ServiceStack.Text/DateTimeExtensions.cs +++ b/src/ServiceStack.Text/DateTimeExtensions.cs @@ -26,7 +26,7 @@ public static class DateTimeExtensions public static long ToUnixTime(this DateTime dateTime) { - return (TimeZoneInfo.ConvertTimeToUtc(dateTime).Ticks - UnixEpoch) / TimeSpan.TicksPerSecond; + return (dateTime.ToStableUniversalTime().Ticks - UnixEpoch) / TimeSpan.TicksPerSecond; } public static DateTime FromUnixTime(this double unixTime) @@ -36,7 +36,7 @@ public static DateTime FromUnixTime(this double unixTime) public static long ToUnixTimeMs(this DateTime dateTime) { - return (TimeZoneInfo.ConvertTimeToUtc(dateTime).Ticks - UnixEpoch) / TimeSpan.TicksPerMillisecond; + return (dateTime.ToStableUniversalTime().Ticks - UnixEpoch) / TimeSpan.TicksPerMillisecond; } public static DateTime FromUnixTimeMs(this double msSince1970) @@ -99,7 +99,7 @@ public static DateTime FromShortestXsdDateTimeString(this string xsdDateTime) public static bool IsEqualToTheSecond(this DateTime dateTime, DateTime otherDateTime) { - return TimeZoneInfo.ConvertTimeToUtc(dateTime).RoundToSecond().Equals(TimeZoneInfo.ConvertTimeToUtc(otherDateTime).RoundToSecond()); + return dateTime.ToStableUniversalTime().RoundToSecond().Equals(otherDateTime.ToStableUniversalTime().RoundToSecond()); } public static string ToTimeOffsetString(this TimeSpan offset, bool includeColon = false) @@ -120,5 +120,17 @@ public static TimeSpan FromTimeOffsetString(this string offsetString) return TimeSpan.Parse(offsetString); } + + public static DateTime ToStableUniversalTime(this DateTime dateTime) + { +#if SILVERLIGHT + // Silverlight 3, 4 and 5 all work ok with DateTime.ToUniversalTime, but have no TimeZoneInfo.ConverTimeToUtc implementation. + return dateTime.ToUniversalTime(); +#else + // .Net 2.0 - 3.5 has an issue with DateTime.ToUniversalTime, but works ok with TimeZoneInfo.ConvertTimeToUtc. + // .Net 4.0+ does this under the hood anyway. + return TimeZoneInfo.ConvertTimeToUtc(dateTime); +#endif + } } } \ No newline at end of file diff --git a/tests/ServiceStack.Text.Tests/Utils/DateTimeSerializerTests.cs b/tests/ServiceStack.Text.Tests/Utils/DateTimeSerializerTests.cs index c67965882..7a5cbd71a 100644 --- a/tests/ServiceStack.Text.Tests/Utils/DateTimeSerializerTests.cs +++ b/tests/ServiceStack.Text.Tests/Utils/DateTimeSerializerTests.cs @@ -40,12 +40,12 @@ public void ToShortestXsdDateTimeString_works() const string shortDateString = "1979-05-09"; var shortDateTime = new DateTime(1979, 5, 9, 0, 0, 1, DateTimeKind.Utc); - var shortDateTimeString = shortDateTime.Equals(TimeZoneInfo.ConvertTimeToUtc(shortDateTime)) + var shortDateTimeString = shortDateTime.Equals(shortDateTime.ToStableUniversalTime()) ? "1979-05-09T00:00:01Z" : "1979-05-08T23:00:01Z"; var longDateTime = new DateTime(1979, 5, 9, 0, 0, 0, 1, DateTimeKind.Utc); - var longDateTimeString = longDateTime.Equals(TimeZoneInfo.ConvertTimeToUtc(longDateTime)) + var longDateTimeString = longDateTime.Equals(longDateTime.ToStableUniversalTime()) ? "1979-05-09T00:00:00.001Z" : "1979-05-08T23:00:00.001Z"; @@ -58,7 +58,7 @@ public void ToShortestXsdDateTimeString_works() public void Utc_Local_Equals() { var now = DateTime.Now; - var utcNow = TimeZoneInfo.ConvertTimeToUtc(now); + var utcNow = now.ToStableUniversalTime(); Assert.That(now.Ticks, Is.EqualTo(utcNow.Ticks), "Ticks are different"); Assert.That(now, Is.EqualTo(utcNow), "DateTimes are different"); @@ -122,7 +122,7 @@ public void AssertDateIsEqual(int whichDate) //Don't test short dates without time to UTC as you lose precision var shortDateStr = dateTime.ToString(DateTimeSerializer.ShortDateTimeFormat); - var shortDateTimeStr = TimeZoneInfo.ConvertTimeToUtc(dateTime).ToString(DateTimeSerializer.XsdDateTimeFormatSeconds); + var shortDateTimeStr = dateTime.ToStableUniversalTime().ToString(DateTimeSerializer.XsdDateTimeFormatSeconds); var longDateTimeStr = DateTimeSerializer.ToXsdDateTimeString(dateTime); var shortestDateStr = DateTimeSerializer.ToShortestXsdDateTimeString(dateTime); @@ -135,14 +135,14 @@ public void AssertDateIsEqual(int whichDate) Assert.That(shortDate, Is.EqualTo(dateTime.Date)); - var shortDateTimeUtc = TimeZoneInfo.ConvertTimeToUtc(shortDateTime); + var shortDateTimeUtc = shortDateTime.ToStableUniversalTime(); Assert.That(shortDateTimeUtc, Is.EqualTo( new DateTime( shortDateTimeUtc.Year, shortDateTimeUtc.Month, shortDateTimeUtc.Day, shortDateTimeUtc.Hour, shortDateTimeUtc.Minute, shortDateTimeUtc.Second, shortDateTimeUtc.Millisecond, DateTimeKind.Utc))); - Assert.That(TimeZoneInfo.ConvertTimeToUtc(longDateTime), Is.EqualTo(TimeZoneInfo.ConvertTimeToUtc(dateTime))); + Assert.That(longDateTime.ToStableUniversalTime(), Is.EqualTo(dateTime.ToStableUniversalTime())); var toDateTime = DateTimeSerializer.ParseShortestXsdDateTime(shortestDateStr); AssertDatesAreEqual(toDateTime, dateTime, "shortestDate"); @@ -158,7 +158,7 @@ public void AssertDateIsEqual(int whichDate) private void AssertDatesAreEqual(DateTime toDateTime, DateTime dateTime, string which) { - Assert.That(TimeZoneInfo.ConvertTimeToUtc(toDateTime).RoundToMs(), Is.EqualTo(TimeZoneInfo.ConvertTimeToUtc(dateTime).RoundToMs()), which); + Assert.That(toDateTime.ToStableUniversalTime().RoundToMs(), Is.EqualTo(dateTime.ToStableUniversalTime().RoundToMs()), which); } } } \ No newline at end of file