From 83450c03b0603e9fa1be4339d323b3bcd4485ff8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=92=D0=B8=D1=82=D0=B0=D0=BB=D0=B8=D0=B9=20=D0=A7=D0=B0?= =?UTF-8?q?=D0=B1=D0=B0=D0=BD?= Date: Mon, 23 Sep 2024 17:07:38 +0300 Subject: [PATCH] fix: set behavior depending on timeZoneInfo --- .../Edm/EdmPrimitiveHelper.cs | 19 ++++++++-- .../Edm/EdmPrimitiveHelperTests.cs | 36 ++++++++++++++++++- 2 files changed, 52 insertions(+), 3 deletions(-) diff --git a/src/Microsoft.AspNetCore.OData/Edm/EdmPrimitiveHelper.cs b/src/Microsoft.AspNetCore.OData/Edm/EdmPrimitiveHelper.cs index 1580ae42b..f607d600c 100644 --- a/src/Microsoft.AspNetCore.OData/Edm/EdmPrimitiveHelper.cs +++ b/src/Microsoft.AspNetCore.OData/Edm/EdmPrimitiveHelper.cs @@ -105,8 +105,12 @@ public static object ConvertPrimitiveValue(object value, Type type, TimeZoneInfo { DateTimeOffset dateTimeOffsetValue = (DateTimeOffset)value; TimeZoneInfo timeZone = timeZoneInfo ?? TimeZoneInfo.Local; + dateTimeOffsetValue = TimeZoneInfo.ConvertTime(dateTimeOffsetValue, timeZone); - return DateTime.SpecifyKind(dateTimeOffsetValue.DateTime, DateTimeKind.Utc); + + var dateTimeKind = GetTargetDateTimeKind(timeZone); + + return DateTime.SpecifyKind(dateTimeOffsetValue.DateTime, dateTimeKind); } if (value is Date) @@ -183,4 +187,15 @@ public static object ConvertPrimitiveValue(object value, Type type, TimeZoneInfo } } } -} + + private static DateTimeKind GetTargetDateTimeKind(TimeZoneInfo timeZone) + { + if (timeZone.Equals(TimeZoneInfo.Local)) + return DateTimeKind.Local; + + if (timeZone.Equals(TimeZoneInfo.Utc)) + return DateTimeKind.Utc; + + return DateTimeKind.Unspecified; + } +} \ No newline at end of file diff --git a/test/Microsoft.AspNetCore.OData.Tests/Edm/EdmPrimitiveHelperTests.cs b/test/Microsoft.AspNetCore.OData.Tests/Edm/EdmPrimitiveHelperTests.cs index f864d73a9..6b67ca1e8 100644 --- a/test/Microsoft.AspNetCore.OData.Tests/Edm/EdmPrimitiveHelperTests.cs +++ b/test/Microsoft.AspNetCore.OData.Tests/Edm/EdmPrimitiveHelperTests.cs @@ -126,7 +126,7 @@ public void ConvertDateTimeValue_NonStandardPrimitives_DefaultTimeZoneInfo(DateT [Theory] [MemberData(nameof(ConvertDateTime_NonStandardPrimitives_Data))] - public void ConvertDateTimeValue_ExplicitUtc(DateTimeOffset valueToConvert) + public void ConvertDateTimeValue_ImplicitKind(DateTimeOffset valueToConvert) { //Some databases (for example, Npgsql) require an explicit indication of Kind = Utc //and do not accept Local and Unspecified in the new versions of the framework @@ -136,6 +136,40 @@ public void ConvertDateTimeValue_ExplicitUtc(DateTimeOffset valueToConvert) // Arrange & Act object actual = EdmPrimitiveHelper.ConvertPrimitiveValue(valueToConvert, typeof(DateTime)); + // Assert + DateTime dt = Assert.IsType(actual); + Assert.Equal(DateTimeKind.Local, dt.Kind); + } + + [Theory] + [MemberData(nameof(ConvertDateTime_NonStandardPrimitives_Data))] + public void ConvertDateTimeValue_ExplicitLocalKind(DateTimeOffset valueToConvert) + { + //Some databases (for example, Npgsql) require an explicit indication of Kind = Utc + //and do not accept Local and Unspecified in the new versions of the framework + + //example: Cannot write DateTime with Kind=Unspecified to PostgreSQL type 'timestamp with time zone', only UTC is supported + + // Arrange & Act + object actual = EdmPrimitiveHelper.ConvertPrimitiveValue(valueToConvert, typeof(DateTime), TimeZoneInfo.Local); + + // Assert + DateTime dt = Assert.IsType(actual); + Assert.Equal(DateTimeKind.Local, dt.Kind); + } + + [Theory] + [MemberData(nameof(ConvertDateTime_NonStandardPrimitives_Data))] + public void ConvertDateTimeValue_ExplicitUtcKind(DateTimeOffset valueToConvert) + { + //Some databases (for example, Npgsql) require an explicit indication of Kind = Utc + //and do not accept Local and Unspecified in the new versions of the framework + + //example: Cannot write DateTime with Kind=Unspecified to PostgreSQL type 'timestamp with time zone', only UTC is supported + + // Arrange & Act + object actual = EdmPrimitiveHelper.ConvertPrimitiveValue(valueToConvert, typeof(DateTime), TimeZoneInfo.Utc); + // Assert DateTime dt = Assert.IsType(actual); Assert.Equal(DateTimeKind.Utc, dt.Kind);