Browse Source

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

pull/24049/head
maliming 9 months 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 try
{ {
var timezoneInfo = _timezoneProvider.GetTimeZoneInfo(_currentTimezoneProvider.TimeZone); var timezoneInfo = _timezoneProvider.GetTimeZoneInfo(_currentTimezoneProvider.TimeZone);
dateTime = new DateTimeOffset(dateTime, timezoneInfo.BaseUtcOffset).UtcDateTime; dateTime = new DateTimeOffset(dateTime, timezoneInfo.GetUtcOffset(dateTime)).UtcDateTime;
} }
catch catch
{ {

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

@ -130,7 +130,7 @@ public class AbpDateTimeConverter : DateTimeConverterBase, ITransientDependency
try try
{ {
var timezoneInfo = _timezoneProvider.GetTimeZoneInfo(_currentTimezoneProvider.TimeZone); var timezoneInfo = _timezoneProvider.GetTimeZoneInfo(_currentTimezoneProvider.TimeZone);
dateTime = new DateTimeOffset(dateTime, timezoneInfo.BaseUtcOffset).UtcDateTime; dateTime = new DateTimeOffset(dateTime, timezoneInfo.GetUtcOffset(dateTime)).UtcDateTime;
} }
catch 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 try
{ {
var timezoneInfo = TimezoneProvider.GetTimeZoneInfo(CurrentTimezoneProvider.TimeZone); var timezoneInfo = TimezoneProvider.GetTimeZoneInfo(CurrentTimezoneProvider.TimeZone);
dateTime = new DateTimeOffset(dateTime, timezoneInfo.BaseUtcOffset).UtcDateTime; dateTime = new DateTimeOffset(dateTime, timezoneInfo.GetUtcOffset(dateTime)).UtcDateTime;
} }
catch 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(); input.InnerModel.Time4.ToString("O").ToLower();
} }
[HttpPost("Guid_Json_Test")] [HttpPost("Guid_Json_Test")]
public GuidJsonModel Guid_Json_Test([FromBody] GuidJsonModel input) 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] [Fact]
public async Task DateTimeKind_Test() 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); response.StatusCode.ShouldBe(HttpStatusCode.OK);
var resultAsString = await response.Content.ReadAsStringAsync(); var resultAsString = await response.Content.ReadAsStringAsync();
@ -29,19 +29,19 @@ public abstract class ModelBindingController_Tests : AspNetCoreMvcTestBase
[Fact] [Fact]
public async Task DateTimeKind_WithTimezone_Test() 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); response.StatusCode.ShouldBe(HttpStatusCode.OK);
var resultAsString = await response.Content.ReadAsStringAsync(); var resultAsString = await response.Content.ReadAsStringAsync();
var dateTime = new DateTime(2010, 1, 1, 0, 0, 0, DateTimeKind.Unspecified); var dateTime = new DateTime(2020, 1, 1, 0, 0, 0, DateTimeKind.Unspecified);
switch(Kind) switch (Kind)
{ {
case DateTimeKind.Utc: 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; break;
case DateTimeKind.Local: 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; break;
} }
@ -52,7 +52,7 @@ public abstract class ModelBindingController_Tests : AspNetCoreMvcTestBase
public async Task NullableDateTimeKind_Test() public async Task NullableDateTimeKind_Test()
{ {
var response = 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); response.StatusCode.ShouldBe(HttpStatusCode.OK);
var resultAsString = await response.Content.ReadAsStringAsync(); var resultAsString = await response.Content.ReadAsStringAsync();
@ -63,19 +63,19 @@ public abstract class ModelBindingController_Tests : AspNetCoreMvcTestBase
public async Task NullableDateTimeKind_WithTimezone_Test() public async Task NullableDateTimeKind_WithTimezone_Test()
{ {
var response = 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); response.StatusCode.ShouldBe(HttpStatusCode.OK);
var resultAsString = await response.Content.ReadAsStringAsync(); var resultAsString = await response.Content.ReadAsStringAsync();
var dateTime = new DateTime(2010, 1, 1, 0, 0, 0, DateTimeKind.Unspecified); var dateTime = new DateTime(2020, 1, 1, 0, 0, 0, DateTimeKind.Unspecified);
switch(Kind) switch (Kind)
{ {
case DateTimeKind.Utc: 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; break;
case DateTimeKind.Local: 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; break;
} }
@ -87,11 +87,11 @@ public abstract class ModelBindingController_Tests : AspNetCoreMvcTestBase
{ {
var response = var response =
await Client.GetAsync( 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); response.StatusCode.ShouldBe(HttpStatusCode.OK);
var resultAsString = await response.Content.ReadAsStringAsync(); 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 //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()); resultAsString.ShouldBe(DateTimeKind.Utc.ToString().ToLower());
} }
@ -101,11 +101,11 @@ public abstract class ModelBindingController_Tests : AspNetCoreMvcTestBase
{ {
var response = var response =
await Client.GetAsync( 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); response.StatusCode.ShouldBe(HttpStatusCode.OK);
var resultAsString = await response.Content.ReadAsStringAsync(); 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 //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()); resultAsString.ShouldBe(DateTimeKind.Utc.ToString().ToLower());
} }
@ -114,14 +114,14 @@ public abstract class ModelBindingController_Tests : AspNetCoreMvcTestBase
public async Task ComplexTypeDateTimeKind_Test() public async Task ComplexTypeDateTimeKind_Test()
{ {
var response = await Client.GetAsync("/api/model-Binding-test/ComplexTypeDateTimeKind?" + var response = await Client.GetAsync("/api/model-Binding-test/ComplexTypeDateTimeKind?" +
"Time1=2010-01-01T00:00:00Z&" + "Time1=2020-01-01T00:00:00Z&" +
"Time2=2010-01-01T00:00:00Z&" + "Time2=2020-01-01T00:00:00Z&" +
"Time3=2010-01-01T00:00:00Z&" + "Time3=2020-01-01T00:00:00Z&" +
"InnerModel.Time4=2010-01-01T00:00:00Z"); "InnerModel.Time4=2020-01-01T00:00:00Z");
response.StatusCode.ShouldBe(HttpStatusCode.OK); response.StatusCode.ShouldBe(HttpStatusCode.OK);
var resultAsString = await response.Content.ReadAsStringAsync(); 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 //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"); resultAsString.ShouldBe($"utc_{Kind.ToString().ToLower()}_{Kind.ToString().ToLower()}_utc");
} }
@ -129,7 +129,7 @@ public abstract class ModelBindingController_Tests : AspNetCoreMvcTestBase
[Fact] [Fact]
public async Task ComplexTypeDateTimeKind_JSON_Test() 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", var response = await Client.PostAsync("/api/model-Binding-test/ComplexTypeDateTimeKind_JSON",
new StringContent(JsonSerializer.Serialize( new StringContent(JsonSerializer.Serialize(
new GetDateTimeKindModel new GetDateTimeKindModel
@ -152,7 +152,7 @@ public abstract class ModelBindingController_Tests : AspNetCoreMvcTestBase
[Fact] [Fact]
public async Task ComplexTypeDateTimeKind_JSON_WithTimezone_Test() 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", var response = await Client.PostAsync("/api/model-Binding-test/ComplexTypeDateTimeKind_JSON_WithResult?__timezone=Europe/Istanbul",
new StringContent(JsonSerializer.Serialize( new StringContent(JsonSerializer.Serialize(
new GetDateTimeKindModel new GetDateTimeKindModel
@ -170,14 +170,14 @@ public abstract class ModelBindingController_Tests : AspNetCoreMvcTestBase
response.StatusCode.ShouldBe(HttpStatusCode.OK); response.StatusCode.ShouldBe(HttpStatusCode.OK);
var resultAsString = await response.Content.ReadAsStringAsync(); var resultAsString = await response.Content.ReadAsStringAsync();
var dateTime = new DateTime(2010, 1, 1, 0, 0, 0, DateTimeKind.Unspecified); var dateTime = new DateTime(2020, 1, 1, 0, 0, 0, DateTimeKind.Unspecified);
switch(Kind) switch (Kind)
{ {
case DateTimeKind.Utc: 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; break;
case DateTimeKind.Local: 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; break;
} }

Loading…
Cancel
Save