Made time zone conversion more rubust.

This commit is contained in:
Daniel Stolt
2014-08-04 02:41:33 +02:00
parent ef5ccaadfe
commit e2bc40305c
2 changed files with 69 additions and 33 deletions

View File

@@ -10,6 +10,7 @@ using Autofac;
using NUnit.Framework;
using Orchard.Localization.Models;
using Orchard.Localization.Services;
using Orchard.Services;
namespace Orchard.Tests.Localization {
@@ -25,10 +26,10 @@ namespace Orchard.Tests.Localization {
[Description("Date component is decremented by one day when converting to time zone with negative offset greater than time component.")]
public void ConvertToSiteTimeZoneTest01() {
var timeZone = TimeZoneInfo.FindSystemTimeZoneById("Pacific Standard Time");
Assert.That(timeZone.BaseUtcOffset, Is.LessThan(TimeSpan.FromHours(-3)));
var container = TestHelpers.InitializeContainer(null, null, timeZone);
var target = container.Resolve<IDateLocalizationServices>();
var dateTimeUtc = new DateTime(1998, 1, 15, 3, 0, 0, DateTimeKind.Utc);
Assert.That(timeZone.GetUtcOffset(dateTimeUtc), Is.LessThan(TimeSpan.FromHours(-3)));
var target = container.Resolve<IDateLocalizationServices>();
var result = target.ConvertToSiteTimeZone(dateTimeUtc);
Assert.AreEqual(14, result.Day);
}
@@ -37,10 +38,10 @@ namespace Orchard.Tests.Localization {
[Description("Date component is incremented by one day when converting to time zone with positive offset greater than 24 hours minus time component.")]
public void ConvertToSiteTimeZoneTest02() {
var timeZone = TimeZoneInfo.FindSystemTimeZoneById("India Standard Time");
Assert.That(timeZone.BaseUtcOffset, Is.GreaterThan(TimeSpan.FromHours(3)));
var container = TestHelpers.InitializeContainer(null, null, timeZone);
var target = container.Resolve<IDateLocalizationServices>();
var dateTimeUtc = new DateTime(1998, 1, 15, 21, 0, 0, DateTimeKind.Utc);
Assert.That(timeZone.GetUtcOffset(dateTimeUtc), Is.GreaterThan(TimeSpan.FromHours(3)));
var target = container.Resolve<IDateLocalizationServices>();
var result = target.ConvertToSiteTimeZone(dateTimeUtc);
Assert.AreEqual(16, result.Day);
}
@@ -49,10 +50,10 @@ namespace Orchard.Tests.Localization {
[Description("DateTime which is DateTimeKind.Utc is converted to DateTimeKind.Local with offset when target time zone is not UTC.")]
public void ConvertToSiteTimeZoneTest03() {
var timeZone = TimeZoneInfo.FindSystemTimeZoneById("Central European Standard Time");
Assert.That(timeZone.BaseUtcOffset, Is.Not.EqualTo(TimeSpan.Zero));
var container = TestHelpers.InitializeContainer(null, null, timeZone);
var target = container.Resolve<IDateLocalizationServices>();
var dateTimeUtc = new DateTime(1998, 1, 15, 3, 0, 0, DateTimeKind.Utc);
Assert.That(timeZone.GetUtcOffset(dateTimeUtc), Is.Not.EqualTo(TimeSpan.Zero));
var target = container.Resolve<IDateLocalizationServices>();
var result = target.ConvertToSiteTimeZone(dateTimeUtc);
Assert.AreEqual(DateTimeKind.Local, result.Kind);
Assert.AreEqual(dateTimeUtc.Hour + timeZone.BaseUtcOffset.Hours, result.Hour);
@@ -62,10 +63,10 @@ namespace Orchard.Tests.Localization {
[Description("DateTime which is DateTimeKind.Utc is not converted when target time zone is UTC.")]
public void ConvertToSiteTimeZoneTest04() {
var timeZone = TimeZoneInfo.FindSystemTimeZoneById("UTC");
Assert.That(timeZone.BaseUtcOffset, Is.EqualTo(TimeSpan.Zero));
var container = TestHelpers.InitializeContainer(null, null, timeZone);
var target = container.Resolve<IDateLocalizationServices>();
var dateTimeUtc = new DateTime(1998, 1, 15, 3, 0, 0, DateTimeKind.Utc);
Assert.That(timeZone.GetUtcOffset(dateTimeUtc), Is.EqualTo(TimeSpan.Zero));
var target = container.Resolve<IDateLocalizationServices>();
var result = target.ConvertToSiteTimeZone(dateTimeUtc);
Assert.AreEqual(DateTimeKind.Utc, result.Kind);
Assert.AreEqual(dateTimeUtc, result);
@@ -75,10 +76,10 @@ namespace Orchard.Tests.Localization {
[Description("DateTime which is DateTimeKind.Unspecified is converted to DateTimeKind.Local with offset when target time zone is not UTC.")]
public void ConvertToSiteTimeZoneTest05() {
var timeZone = TimeZoneInfo.FindSystemTimeZoneById("Central European Standard Time");
Assert.That(timeZone.BaseUtcOffset, Is.Not.EqualTo(TimeSpan.Zero));
var container = TestHelpers.InitializeContainer(null, null, timeZone);
var target = container.Resolve<IDateLocalizationServices>();
var dateTimeUtc = new DateTime(1998, 1, 15, 3, 0, 0, DateTimeKind.Unspecified);
Assert.That(timeZone.GetUtcOffset(dateTimeUtc), Is.Not.EqualTo(TimeSpan.Zero));
var target = container.Resolve<IDateLocalizationServices>();
var result = target.ConvertToSiteTimeZone(dateTimeUtc);
Assert.AreEqual(DateTimeKind.Local, result.Kind);
Assert.AreEqual(dateTimeUtc.Hour + timeZone.BaseUtcOffset.Hours, result.Hour);
@@ -88,10 +89,10 @@ namespace Orchard.Tests.Localization {
[Description("DateTime which is DateTimeKind.Unspecified is converted to DateTimeKind.Utc with no offset when target time zone is UTC.")]
public void ConvertToSiteTimeZoneTest06() {
var timeZone = TimeZoneInfo.FindSystemTimeZoneById("UTC");
Assert.That(timeZone.BaseUtcOffset, Is.EqualTo(TimeSpan.Zero));
var container = TestHelpers.InitializeContainer(null, null, timeZone);
var target = container.Resolve<IDateLocalizationServices>();
var dateTimeUtc = new DateTime(1998, 1, 15, 3, 0, 0, DateTimeKind.Unspecified);
Assert.That(timeZone.GetUtcOffset(dateTimeUtc), Is.EqualTo(TimeSpan.Zero));
var target = container.Resolve<IDateLocalizationServices>();
var result = target.ConvertToSiteTimeZone(dateTimeUtc);
Assert.AreEqual(DateTimeKind.Utc, result.Kind);
Assert.AreEqual(dateTimeUtc, result);
@@ -101,10 +102,10 @@ namespace Orchard.Tests.Localization {
[Description("DateTime which is already DateTimeKind.Local is never converted.")]
public void ConvertToSiteTimeZoneTest07() {
var timeZone = TimeZoneInfo.FindSystemTimeZoneById("Pacific Standard Time");
Assert.That(timeZone.BaseUtcOffset, Is.Not.EqualTo(TimeSpan.Zero));
var container = TestHelpers.InitializeContainer(null, null, timeZone);
var target = container.Resolve<IDateLocalizationServices>();
var dateTimeUtc = new DateTime(1998, 1, 15, 3, 0, 0, DateTimeKind.Local);
Assert.That(timeZone.GetUtcOffset(dateTimeUtc), Is.Not.EqualTo(TimeSpan.Zero));
var target = container.Resolve<IDateLocalizationServices>();
var result = target.ConvertToSiteTimeZone(dateTimeUtc);
Assert.AreEqual(DateTimeKind.Local, result.Kind);
Assert.AreEqual(dateTimeUtc, result);
@@ -117,10 +118,10 @@ namespace Orchard.Tests.Localization {
if (timeZone == TimeZoneInfo.Local) {
timeZone = TimeZoneInfo.FindSystemTimeZoneById("Pacific Standard Time");
}
Assert.That(timeZone.BaseUtcOffset, Is.Not.EqualTo(TimeSpan.Zero));
var container = TestHelpers.InitializeContainer(null, null, timeZone);
var target = container.Resolve<IDateLocalizationServices>();
var dateTimeUtc = new DateTime(1998, 1, 15, 3, 0, 0, DateTimeKind.Utc);
Assert.That(timeZone.GetUtcOffset(dateTimeUtc), Is.Not.EqualTo(TimeSpan.Zero));
var target = container.Resolve<IDateLocalizationServices>();
var result = target.ConvertToSiteTimeZone(dateTimeUtc);
Assert.AreEqual(DateTimeKind.Local, result.Kind);
}
@@ -129,10 +130,10 @@ namespace Orchard.Tests.Localization {
[Description("Date component is incremented by one day when converting from time zone with negative offset greater than 24 hours minus time component.")]
public void ConvertFromSiteTimeZoneTest01() {
var timeZone = TimeZoneInfo.FindSystemTimeZoneById("Pacific Standard Time");
Assert.That(timeZone.BaseUtcOffset, Is.LessThan(TimeSpan.FromHours(-3)));
var container = TestHelpers.InitializeContainer(null, null, timeZone);
var target = container.Resolve<IDateLocalizationServices>();
var dateTimeLocal = new DateTime(1998, 1, 15, 21, 0, 0, DateTimeKind.Local);
Assert.That(timeZone.GetUtcOffset(dateTimeLocal), Is.LessThan(TimeSpan.FromHours(-3)));
var target = container.Resolve<IDateLocalizationServices>();
var result = target.ConvertFromSiteTimeZone(dateTimeLocal);
Assert.AreEqual(16, result.Day);
}
@@ -141,10 +142,10 @@ namespace Orchard.Tests.Localization {
[Description("Date component is decremented by one day when converting from time zone with positive offset greater than time component.")]
public void ConvertFromSiteTimeZoneTest02() {
var timeZone = TimeZoneInfo.FindSystemTimeZoneById("India Standard Time");
Assert.That(timeZone.BaseUtcOffset, Is.GreaterThan(TimeSpan.FromHours(3)));
var container = TestHelpers.InitializeContainer(null, null, timeZone);
var target = container.Resolve<IDateLocalizationServices>();
var dateTimeLocal = new DateTime(1998, 1, 15, 3, 0, 0, DateTimeKind.Local);
Assert.That(timeZone.GetUtcOffset(dateTimeLocal), Is.GreaterThan(TimeSpan.FromHours(3)));
var target = container.Resolve<IDateLocalizationServices>();
var result = target.ConvertFromSiteTimeZone(dateTimeLocal);
Assert.AreEqual(14, result.Day);
}
@@ -153,10 +154,10 @@ namespace Orchard.Tests.Localization {
[Description("DateTime which is DateTimeKind.Local is converted to DateTimeKind.Utc with offset when target time zone is not UTC.")]
public void ConvertFromSiteTimeZoneTest03() {
var timeZone = TimeZoneInfo.FindSystemTimeZoneById("Central European Standard Time");
Assert.That(timeZone.BaseUtcOffset, Is.Not.EqualTo(TimeSpan.Zero));
var container = TestHelpers.InitializeContainer(null, null, timeZone);
var target = container.Resolve<IDateLocalizationServices>();
var dateTimeLocal = new DateTime(1998, 1, 15, 21, 0, 0, DateTimeKind.Local);
Assert.That(timeZone.GetUtcOffset(dateTimeLocal), Is.Not.EqualTo(TimeSpan.Zero));
var target = container.Resolve<IDateLocalizationServices>();
var result = target.ConvertFromSiteTimeZone(dateTimeLocal);
Assert.AreEqual(DateTimeKind.Utc, result.Kind);
Assert.AreEqual(dateTimeLocal.Hour - timeZone.BaseUtcOffset.Hours, result.Hour);
@@ -166,10 +167,10 @@ namespace Orchard.Tests.Localization {
[Description("DateTime which is DateTimeKind.Local is converted to DateTimeKind.Utc with no offset when target time zone is UTC.")]
public void ConvertFromSiteTimeZoneTest04() {
var timeZone = TimeZoneInfo.FindSystemTimeZoneById("UTC");
Assert.That(timeZone.BaseUtcOffset, Is.EqualTo(TimeSpan.Zero));
var container = TestHelpers.InitializeContainer(null, null, timeZone);
var target = container.Resolve<IDateLocalizationServices>();
var dateTimeLocal = new DateTime(1998, 1, 15, 21, 0, 0, DateTimeKind.Local);
Assert.That(timeZone.GetUtcOffset(dateTimeLocal), Is.EqualTo(TimeSpan.Zero));
var target = container.Resolve<IDateLocalizationServices>();
var result = target.ConvertFromSiteTimeZone(dateTimeLocal);
Assert.AreEqual(DateTimeKind.Utc, result.Kind);
Assert.AreEqual(dateTimeLocal.Hour, result.Hour);
@@ -180,10 +181,10 @@ namespace Orchard.Tests.Localization {
[Description("DateTime which is DateTimeKind.Unspecified is converted to DateTimeKind.Utc with offset when target time zone is not UTC.")]
public void ConvertFromSiteTimeZoneTest05() {
var timeZone = TimeZoneInfo.FindSystemTimeZoneById("Central European Standard Time");
Assert.That(timeZone.BaseUtcOffset, Is.Not.EqualTo(TimeSpan.Zero));
var container = TestHelpers.InitializeContainer(null, null, timeZone);
var target = container.Resolve<IDateLocalizationServices>();
var dateTimeLocal = new DateTime(1998, 1, 15, 21, 0, 0, DateTimeKind.Unspecified);
Assert.That(timeZone.GetUtcOffset(dateTimeLocal), Is.Not.EqualTo(TimeSpan.Zero));
var target = container.Resolve<IDateLocalizationServices>();
var result = target.ConvertFromSiteTimeZone(dateTimeLocal);
Assert.AreEqual(DateTimeKind.Utc, result.Kind);
Assert.AreEqual(dateTimeLocal.Hour - timeZone.BaseUtcOffset.Hours, result.Hour);
@@ -193,10 +194,10 @@ namespace Orchard.Tests.Localization {
[Description("DateTime which is DateTimeKind.Unspecified is converted to DateTimeKind.Utc with no offset when target time zone is UTC.")]
public void ConvertFromSiteTimeZoneTest06() {
var timeZone = TimeZoneInfo.FindSystemTimeZoneById("UTC");
Assert.That(timeZone.BaseUtcOffset, Is.EqualTo(TimeSpan.Zero));
var container = TestHelpers.InitializeContainer(null, null, timeZone);
var target = container.Resolve<IDateLocalizationServices>();
var dateTimeLocal = new DateTime(1998, 1, 15, 21, 0, 0, DateTimeKind.Unspecified);
Assert.That(timeZone.GetUtcOffset(dateTimeLocal), Is.EqualTo(TimeSpan.Zero));
var target = container.Resolve<IDateLocalizationServices>();
var result = target.ConvertFromSiteTimeZone(dateTimeLocal);
Assert.AreEqual(DateTimeKind.Utc, result.Kind);
Assert.AreEqual(dateTimeLocal.Hour, result.Hour);
@@ -207,13 +208,37 @@ namespace Orchard.Tests.Localization {
[Description("DateTime which is already DateTimeKind.Utc is never converted.")]
public void ConvertFromSiteTimeZoneTest07() {
var timeZone = TimeZoneInfo.FindSystemTimeZoneById("Central European Standard Time");
Assert.That(timeZone.BaseUtcOffset, Is.Not.EqualTo(TimeSpan.Zero));
var container = TestHelpers.InitializeContainer(null, null, timeZone);
var target = container.Resolve<IDateLocalizationServices>();
var dateTimeLocal = new DateTime(1998, 1, 15, 21, 0, 0, DateTimeKind.Utc);
Assert.That(timeZone.GetUtcOffset(dateTimeLocal), Is.Not.EqualTo(TimeSpan.Zero));
var target = container.Resolve<IDateLocalizationServices>();
var result = target.ConvertFromSiteTimeZone(dateTimeLocal);
Assert.AreEqual(DateTimeKind.Utc, result.Kind);
Assert.AreEqual(dateTimeLocal, result);
}
[Test]
[Description("Converting to Gregorian calendar yields a DateTimeParts instance equivalent to the original DateTime.")]
public void ConvertToSiteCalendarTest01() {
Assert.Inconclusive();
}
[Test]
[Description("Converting to non-Gregorian calendar yields a DateTimeParts instance with correct values.")]
public void ConvertToSiteCalendarTest02() {
Assert.Inconclusive();
}
[Test]
[Description("Converting from Gregorian calendar yields a DateTime equivalent to the original DateTimeParts instance.")]
public void ConvertFromSiteCalendarTest01() {
Assert.Inconclusive();
}
[Test]
[Description("Converting from non-Gregorian calendar yields a DateTime with correct values.")]
public void ConvertFromSiteCalendarTest02() {
Assert.Inconclusive();
}
}
}

View File

@@ -29,6 +29,11 @@ namespace Orchard.Localization.Services {
}
public virtual DateTime ConvertToSiteTimeZone(DateTime dateUtc) {
// Some trickery is necessary for correct handling of DateTimeKind values
// of both input and output dates, because the TimeZoneInfo class' internal
// handling of this is tightly coupled to the configured time zone of
// the local computer, which can differ from the configured time zone of
// the Orchard site.
if (dateUtc.Kind == DateTimeKind.Local) {
return dateUtc;
}
@@ -38,15 +43,21 @@ namespace Orchard.Localization.Services {
}
return dateUtc;
}
var dateLocal = dateUtc + CurrentTimeZone.BaseUtcOffset;
var dateLocal = TimeZoneInfo.ConvertTimeFromUtc(dateUtc, CurrentTimeZone);
return new DateTime(dateLocal.Ticks, DateTimeKind.Local);
}
public virtual DateTime ConvertFromSiteTimeZone(DateTime dateLocal) {
// Some trickery is necessary for correct handling of DateTimeKind values
// of both input and output dates, because the TimeZoneInfo class' internal
// handling of this is tightly coupled to the configured time zone of
// the local computer, which can differ from the configured time zone of
// the Orchard site.
if (dateLocal.Kind == DateTimeKind.Utc) {
return dateLocal;
}
var dateUtc = dateLocal - CurrentTimeZone.BaseUtcOffset;
}
var dateUnspecified = new DateTime(dateLocal.Ticks, DateTimeKind.Unspecified);
var dateUtc = TimeZoneInfo.ConvertTimeToUtc(dateUnspecified, CurrentTimeZone);
return new DateTime(dateUtc.Ticks, DateTimeKind.Utc);
}