Browse Source

Refactor DateTime handling to use GetUtcOffset for accurate timezone adjustments in model binding and JSON converters

pull/24049/head
maliming 1 month ago
parent
commit
84cf25f17b
No known key found for this signature in database GPG Key ID: A646B9CB645ECEA4
  1. 2
      framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ModelBinding/AbpDateTimeModelBinder.cs
  2. 2
      framework/src/Volo.Abp.Json.Newtonsoft/Volo/Abp/Json/Newtonsoft/AbpDateTimeConverter.cs
  3. 2
      framework/src/Volo.Abp.Json.SystemTextJson/Volo/Abp/Json/SystemTextJson/JsonConverters/AbpDateTimeConverterBase.cs
  4. 1
      framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/ModelBinding/ModelBindingController.cs
  5. 54
      framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/ModelBinding/ModelBindingController_Tests.cs

2
framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ModelBinding/AbpDateTimeModelBinder.cs

@ -37,7 +37,7 @@ public class AbpDateTimeModelBinder : IModelBinder
try
{
var timezoneInfo = _timezoneProvider.GetTimeZoneInfo(_currentTimezoneProvider.TimeZone);
dateTime = new DateTimeOffset(dateTime, timezoneInfo.BaseUtcOffset).UtcDateTime;
dateTime = new DateTimeOffset(dateTime, timezoneInfo.GetUtcOffset(dateTime)).UtcDateTime;
}
catch
{

2
framework/src/Volo.Abp.Json.Newtonsoft/Volo/Abp/Json/Newtonsoft/AbpDateTimeConverter.cs

@ -130,7 +130,7 @@ public class AbpDateTimeConverter : DateTimeConverterBase, ITransientDependency
try
{
var timezoneInfo = _timezoneProvider.GetTimeZoneInfo(_currentTimezoneProvider.TimeZone);
dateTime = new DateTimeOffset(dateTime, timezoneInfo.BaseUtcOffset).UtcDateTime;
dateTime = new DateTimeOffset(dateTime, timezoneInfo.GetUtcOffset(dateTime)).UtcDateTime;
}
catch
{

2
framework/src/Volo.Abp.Json.SystemTextJson/Volo/Abp/Json/SystemTextJson/JsonConverters/AbpDateTimeConverterBase.cs

@ -98,7 +98,7 @@ public abstract class AbpDateTimeConverterBase<T> : JsonConverter<T>
try
{
var timezoneInfo = TimezoneProvider.GetTimeZoneInfo(CurrentTimezoneProvider.TimeZone);
dateTime = new DateTimeOffset(dateTime, timezoneInfo.BaseUtcOffset).UtcDateTime;
dateTime = new DateTimeOffset(dateTime, timezoneInfo.GetUtcOffset(dateTime)).UtcDateTime;
}
catch
{

1
framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/ModelBinding/ModelBindingController.cs

@ -89,7 +89,6 @@ public class ModelBindingController : AbpController
input.InnerModel.Time4.ToString("O").ToLower();
}
[HttpPost("Guid_Json_Test")]
public GuidJsonModel Guid_Json_Test([FromBody] GuidJsonModel input)
{

54
framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/ModelBinding/ModelBindingController_Tests.cs

@ -19,7 +19,7 @@ public abstract class ModelBindingController_Tests : AspNetCoreMvcTestBase
[Fact]
public async Task DateTimeKind_Test()
{
var response = await Client.GetAsync("/api/model-Binding-test/DateTimeKind?input=2010-01-01T00:00:00Z");
var response = await Client.GetAsync("/api/model-Binding-test/DateTimeKind?input=2020-01-01T00:00:00Z");
response.StatusCode.ShouldBe(HttpStatusCode.OK);
var resultAsString = await response.Content.ReadAsStringAsync();
@ -29,19 +29,19 @@ public abstract class ModelBindingController_Tests : AspNetCoreMvcTestBase
[Fact]
public async Task DateTimeKind_WithTimezone_Test()
{
var response = await Client.GetAsync("/api/model-Binding-test/DateTimeKind_WithResult?input=2010-01-01T00:00:00&__timezone=Europe/Istanbul");
var response = await Client.GetAsync("/api/model-Binding-test/DateTimeKind_WithResult?input=2020-01-01T00:00:00&__timezone=Europe/Istanbul");
response.StatusCode.ShouldBe(HttpStatusCode.OK);
var resultAsString = await response.Content.ReadAsStringAsync();
var dateTime = new DateTime(2010, 1, 1, 0, 0, 0, DateTimeKind.Unspecified);
switch(Kind)
var dateTime = new DateTime(2020, 1, 1, 0, 0, 0, DateTimeKind.Unspecified);
switch (Kind)
{
case DateTimeKind.Utc:
dateTime = new DateTime(2009, 12, 31, 21, 0, 0, DateTimeKind.Utc); //Turkey is UTC+3
dateTime = new DateTime(2019, 12, 31, 21, 0, 0, DateTimeKind.Utc); //Turkey is UTC+3
break;
case DateTimeKind.Local:
dateTime = new DateTime(2010, 1, 1, 0, 0, 0, DateTimeKind.Local);
dateTime = new DateTime(2020, 1, 1, 0, 0, 0, DateTimeKind.Local);
break;
}
@ -52,7 +52,7 @@ public abstract class ModelBindingController_Tests : AspNetCoreMvcTestBase
public async Task NullableDateTimeKind_Test()
{
var response =
await Client.GetAsync("/api/model-Binding-test/NullableDateTimeKind?input=2010-01-01T00:00:00Z");
await Client.GetAsync("/api/model-Binding-test/NullableDateTimeKind?input=2020-01-01T00:00:00Z");
response.StatusCode.ShouldBe(HttpStatusCode.OK);
var resultAsString = await response.Content.ReadAsStringAsync();
@ -63,19 +63,19 @@ public abstract class ModelBindingController_Tests : AspNetCoreMvcTestBase
public async Task NullableDateTimeKind_WithTimezone_Test()
{
var response =
await Client.GetAsync("/api/model-Binding-test/NullableDateTimeKind_WithResult?input=2010-01-01T00:00:00&__timezone=Europe/Istanbul");
await Client.GetAsync("/api/model-Binding-test/NullableDateTimeKind_WithResult?input=2020-01-01T00:00:00&__timezone=Europe/Istanbul");
response.StatusCode.ShouldBe(HttpStatusCode.OK);
var resultAsString = await response.Content.ReadAsStringAsync();
var dateTime = new DateTime(2010, 1, 1, 0, 0, 0, DateTimeKind.Unspecified);
switch(Kind)
var dateTime = new DateTime(2020, 1, 1, 0, 0, 0, DateTimeKind.Unspecified);
switch (Kind)
{
case DateTimeKind.Utc:
dateTime = new DateTime(2009, 12, 31, 21, 0, 0, DateTimeKind.Utc); //Turkey is UTC+3
dateTime = new DateTime(2019, 12, 31, 21, 0, 0, DateTimeKind.Utc); //Turkey is UTC+3
break;
case DateTimeKind.Local:
dateTime = new DateTime(2010, 1, 1, 0, 0, 0, DateTimeKind.Local);
dateTime = new DateTime(2020, 1, 1, 0, 0, 0, DateTimeKind.Local);
break;
}
@ -87,11 +87,11 @@ public abstract class ModelBindingController_Tests : AspNetCoreMvcTestBase
{
var response =
await Client.GetAsync(
"/api/model-Binding-test/DisableDateTimeNormalizationDateTimeKind?input=2010-01-01T00:00:00Z");
"/api/model-Binding-test/DisableDateTimeNormalizationDateTimeKind?input=2020-01-01T00:00:00Z");
response.StatusCode.ShouldBe(HttpStatusCode.OK);
var resultAsString = await response.Content.ReadAsStringAsync();
//Time parameter(2010-01-01T00:00:00Z) with time zone information, so the default Kind is UTC
//Time parameter(2020-01-01T00:00:00Z) with time zone information, so the default Kind is UTC
//https://docs.microsoft.com/en-us/aspnet/core/migration/31-to-50?view=aspnetcore-3.1&tabs=visual-studio#datetime-values-are-model-bound-as-utc-times
resultAsString.ShouldBe(DateTimeKind.Utc.ToString().ToLower());
}
@ -101,11 +101,11 @@ public abstract class ModelBindingController_Tests : AspNetCoreMvcTestBase
{
var response =
await Client.GetAsync(
"/api/model-Binding-test/DisableDateTimeNormalizationNullableDateTimeKind?input=2010-01-01T00:00:00Z");
"/api/model-Binding-test/DisableDateTimeNormalizationNullableDateTimeKind?input=2020-01-01T00:00:00Z");
response.StatusCode.ShouldBe(HttpStatusCode.OK);
var resultAsString = await response.Content.ReadAsStringAsync();
//Time parameter(2010-01-01T00:00:00Z) with time zone information, so the default Kind is UTC
//Time parameter(2020-01-01T00:00:00Z) with time zone information, so the default Kind is UTC
//https://docs.microsoft.com/en-us/aspnet/core/migration/31-to-50?view=aspnetcore-3.1&tabs=visual-studio#datetime-values-are-model-bound-as-utc-times
resultAsString.ShouldBe(DateTimeKind.Utc.ToString().ToLower());
}
@ -114,14 +114,14 @@ public abstract class ModelBindingController_Tests : AspNetCoreMvcTestBase
public async Task ComplexTypeDateTimeKind_Test()
{
var response = await Client.GetAsync("/api/model-Binding-test/ComplexTypeDateTimeKind?" +
"Time1=2010-01-01T00:00:00Z&" +
"Time2=2010-01-01T00:00:00Z&" +
"Time3=2010-01-01T00:00:00Z&" +
"InnerModel.Time4=2010-01-01T00:00:00Z");
"Time1=2020-01-01T00:00:00Z&" +
"Time2=2020-01-01T00:00:00Z&" +
"Time3=2020-01-01T00:00:00Z&" +
"InnerModel.Time4=2020-01-01T00:00:00Z");
response.StatusCode.ShouldBe(HttpStatusCode.OK);
var resultAsString = await response.Content.ReadAsStringAsync();
//Time parameter(2010-01-01T00:00:00Z) with time zone information, so the default Kind is UTC
//Time parameter(2020-01-01T00:00:00Z) with time zone information, so the default Kind is UTC
//https://docs.microsoft.com/en-us/aspnet/core/migration/31-to-50?view=aspnetcore-3.1&tabs=visual-studio#datetime-values-are-model-bound-as-utc-times
resultAsString.ShouldBe($"utc_{Kind.ToString().ToLower()}_{Kind.ToString().ToLower()}_utc");
}
@ -129,7 +129,7 @@ public abstract class ModelBindingController_Tests : AspNetCoreMvcTestBase
[Fact]
public async Task ComplexTypeDateTimeKind_JSON_Test()
{
var time = DateTime.Parse("2010-01-01T00:00:00Z");
var time = DateTime.Parse("2020-01-01T00:00:00Z");
var response = await Client.PostAsync("/api/model-Binding-test/ComplexTypeDateTimeKind_JSON",
new StringContent(JsonSerializer.Serialize(
new GetDateTimeKindModel
@ -152,7 +152,7 @@ public abstract class ModelBindingController_Tests : AspNetCoreMvcTestBase
[Fact]
public async Task ComplexTypeDateTimeKind_JSON_WithTimezone_Test()
{
var time = DateTime.Parse("2010-01-01T00:00:00");
var time = DateTime.Parse("2020-01-01T00:00:00");
var response = await Client.PostAsync("/api/model-Binding-test/ComplexTypeDateTimeKind_JSON_WithResult?__timezone=Europe/Istanbul",
new StringContent(JsonSerializer.Serialize(
new GetDateTimeKindModel
@ -170,14 +170,14 @@ public abstract class ModelBindingController_Tests : AspNetCoreMvcTestBase
response.StatusCode.ShouldBe(HttpStatusCode.OK);
var resultAsString = await response.Content.ReadAsStringAsync();
var dateTime = new DateTime(2010, 1, 1, 0, 0, 0, DateTimeKind.Unspecified);
switch(Kind)
var dateTime = new DateTime(2020, 1, 1, 0, 0, 0, DateTimeKind.Unspecified);
switch (Kind)
{
case DateTimeKind.Utc:
dateTime = new DateTime(2009, 12, 31, 21, 0, 0, DateTimeKind.Utc); //Turkey is UTC+3
dateTime = new DateTime(2019, 12, 31, 21, 0, 0, DateTimeKind.Utc); //Turkey is UTC+3
break;
case DateTimeKind.Local:
dateTime = new DateTime(2010, 1, 1, 0, 0, 0, DateTimeKind.Local);
dateTime = new DateTime(2020, 1, 1, 0, 0, 0, DateTimeKind.Local);
break;
}

Loading…
Cancel
Save