Properly read and write UTC values for DateTimeOffset (#188)

MS Access does not have a DateTimeOffset data type so the value should be converted to UTC and saved as a normal date/time

This fixes 2 things

Regression in 7.0 series where the DateTimeOffset was being written as Local time and not UTC.
When reading the value and converting from a DateTime, the Offset value ended up being implicitly set to the systems local time zone offset. A DateTimeOffset from a UTC value should actually have an offset of 0. This has been wrong since the 2.2 series
pull/189/head
Christopher Jolly 2 years ago committed by GitHub
parent b7d03c8922
commit 7b6ee168e2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -1,6 +1,6 @@
<Project>
<PropertyGroup Label="Version settings">
<!--
<PropertyGroup Label="Version settings">
<!--
Use the following values for the different release types:
- "alpha"
- "beta"
@ -11,47 +11,47 @@
Bump-up to the next iteration immediately after a release, so that subsequent daily builds are named
correctly.
-->
<VersionPrefix>8.0.0</VersionPrefix>
<PreReleaseVersionLabel>alpha</PreReleaseVersionLabel>
<PreReleaseVersionIteration>2</PreReleaseVersionIteration>
<VersionPrefix>8.0.0</VersionPrefix>
<PreReleaseVersionLabel>alpha</PreReleaseVersionLabel>
<PreReleaseVersionIteration>2</PreReleaseVersionIteration>
<!--
<!--
The following properties will automatically be set by CI builds when appropriate:
OfficialVersion
ContinuousIntegrationTimestamp
BuildSha
-->
</PropertyGroup>
</PropertyGroup>
<!--
<!--
If no version or version suffix or official version has been explicitly set, we generate a version suffix in the following format:
alpha.1.ci.20201004T181121Z+sha.0a1b2c3
-->
<PropertyGroup>
<UseVersionOverride Condition="'$(Version)' != ''">true</UseVersionOverride>
<UseVersionSuffixOverride Condition="'$(VersionSuffix)' != ''">true</UseVersionSuffixOverride>
</PropertyGroup>
<PropertyGroup>
<UseVersionOverride Condition="'$(Version)' != ''">true</UseVersionOverride>
<UseVersionSuffixOverride Condition="'$(VersionSuffix)' != ''">true</UseVersionSuffixOverride>
</PropertyGroup>
<PropertyGroup Label="Version Suffix Handling" Condition="'$(UseVersionOverride)' != 'true' And '$(UseVersionSuffixOverride)' != 'true' And ('$(OfficialVersion)' == '' Or ($(OfficialVersion.Contains('-')) And '$(OfficialVersion)' != '-debug'))">
<VersionSuffix>$(PreReleaseVersionLabel).$(PreReleaseVersionIteration)</VersionSuffix>
<VersionSuffix Condition="'$(ContinuousIntegrationTimestamp)' != ''">$(VersionSuffix).ci.$(ContinuousIntegrationTimestamp)</VersionSuffix>
<VersionSuffix Condition="'$(Configuration)' == 'Debug'">$(VersionSuffix).debug</VersionSuffix>
<VersionSuffix Condition="'$(BuildSha)' != ''">$(VersionSuffix)+sha.$(BuildSha)</VersionSuffix>
</PropertyGroup>
<PropertyGroup Label="Version Suffix Handling" Condition="'$(UseVersionOverride)' != 'true' And '$(UseVersionSuffixOverride)' != 'true' And ('$(OfficialVersion)' == '' Or ($(OfficialVersion.Contains('-')) And '$(OfficialVersion)' != '-debug'))">
<VersionSuffix>$(PreReleaseVersionLabel).$(PreReleaseVersionIteration)</VersionSuffix>
<VersionSuffix Condition="'$(ContinuousIntegrationTimestamp)' != ''">$(VersionSuffix).ci.$(ContinuousIntegrationTimestamp)</VersionSuffix>
<VersionSuffix Condition="'$(Configuration)' == 'Debug'">$(VersionSuffix).debug</VersionSuffix>
<VersionSuffix Condition="'$(BuildSha)' != ''">$(VersionSuffix)+sha.$(BuildSha)</VersionSuffix>
</PropertyGroup>
<PropertyGroup Condition="'$(VersionSuffix)' == ''">
<VersionSuffix Condition="'$(Configuration)' == 'Debug'">debug</VersionSuffix>
</PropertyGroup>
<PropertyGroup Condition="'$(VersionSuffix)' == ''">
<VersionSuffix Condition="'$(Configuration)' == 'Debug'">debug</VersionSuffix>
</PropertyGroup>
<Target Name="EnsureVersionParameters" BeforeTargets="CoreBuild" Condition="'$(UseVersionOverride)' != 'true' And '$(UseVersionSuffixOverride)' != 'true'">
<Error Condition="'$(VersionPrefix)' == ''" Text="The 'VersionPrefix' property needs to be set."/>
<Error Condition="'$(PreReleaseVersionLabel)' == ''" Text="The 'PreReleaseVersionLabel' property needs to be set."/>
<Error Condition="'$(PreReleaseVersionIteration)' == ''" Text="The 'PreReleaseVersionIteration' property needs to be set."/>
<Error Condition="'$(OfficialVersion)' != '' And '$(OfficialVersion)' != '$(VersionPrefix)' And '$(OfficialVersion)' != '$(VersionPrefix)-$(VersionSuffix)'" Text="The 'OfficialVersion' property needs to be identical to the 'VersionPrefix' property or to a combination of the 'VersionPrefix' and the 'VersionSuffix' properties."/>
<!--
<Target Name="EnsureVersionParameters" BeforeTargets="CoreBuild" Condition="'$(UseVersionOverride)' != 'true' And '$(UseVersionSuffixOverride)' != 'true'">
<Error Condition="'$(VersionPrefix)' == ''" Text="The 'VersionPrefix' property needs to be set."/>
<Error Condition="'$(PreReleaseVersionLabel)' == ''" Text="The 'PreReleaseVersionLabel' property needs to be set."/>
<Error Condition="'$(PreReleaseVersionIteration)' == ''" Text="The 'PreReleaseVersionIteration' property needs to be set."/>
<Error Condition="'$(OfficialVersion)' != '' And '$(OfficialVersion)' != '$(VersionPrefix)' And '$(OfficialVersion)' != '$(VersionPrefix)-$(VersionSuffix)'" Text="The 'OfficialVersion' property needs to be identical to the 'VersionPrefix' property or to a combination of the 'VersionPrefix' and the 'VersionSuffix' properties."/>
<!--
<Message Importance="high" Text="VersionPrefix: $(VersionPrefix)" />
<Message Importance="high" Text="VersionSuffix: $(VersionSuffix)" />
<Message Importance="high" Text="Version: $(Version)" />
-->
</Target>
</Target>
</Project>

@ -210,7 +210,7 @@ namespace EntityFrameworkCore.Jet.Data
}
else if (value is DateTime dateTime)
{
return new DateTimeOffset(dateTime);
return new DateTimeOffset(dateTime, TimeSpan.Zero);
}
return (DateTimeOffset)value;

@ -37,7 +37,7 @@ namespace EntityFrameworkCore.Jet.Storage.Internal
// OLE DB can't handle the DateTimeOffset type.
if (parameter.Value is DateTimeOffset dateTimeOffset)
{
parameter.Value = dateTimeOffset.DateTime;
parameter.Value = dateTimeOffset.UtcDateTime;
parameter.DbType = System.Data.DbType.DateTime;
}
@ -50,7 +50,7 @@ namespace EntityFrameworkCore.Jet.Storage.Internal
protected override string GenerateNonNullSqlLiteral(object value)
{
if (value is not DateTimeOffset offset) return base.GenerateNonNullSqlLiteral(value);
var dateTime = offset.DateTime;
var dateTime = offset.UtcDateTime;
return string.Format(CultureInfo.InvariantCulture, DateTimeFormatConst, dateTime);
}
}

@ -10462,6 +10462,10 @@ EntityFrameworkCore.Jet.FunctionalTests.Query.GearsOfWarQueryJetTest.Where_count
EntityFrameworkCore.Jet.FunctionalTests.Query.GearsOfWarQueryJetTest.Where_count_subquery_without_collision(isAsync: True)
EntityFrameworkCore.Jet.FunctionalTests.Query.GearsOfWarQueryJetTest.Where_DateOnly_DayOfWeek(async: False)
EntityFrameworkCore.Jet.FunctionalTests.Query.GearsOfWarQueryJetTest.Where_DateOnly_DayOfWeek(async: True)
EntityFrameworkCore.Jet.FunctionalTests.Query.GearsOfWarQueryJetTest.Where_datetimeoffset_dayofyear_component(isAsync: False)
EntityFrameworkCore.Jet.FunctionalTests.Query.GearsOfWarQueryJetTest.Where_datetimeoffset_dayofyear_component(isAsync: True)
EntityFrameworkCore.Jet.FunctionalTests.Query.GearsOfWarQueryJetTest.Where_datetimeoffset_month_component(isAsync: False)
EntityFrameworkCore.Jet.FunctionalTests.Query.GearsOfWarQueryJetTest.Where_datetimeoffset_month_component(isAsync: True)
EntityFrameworkCore.Jet.FunctionalTests.Query.GearsOfWarQueryJetTest.Where_enum_has_flag_subquery_client_eval(isAsync: False)
EntityFrameworkCore.Jet.FunctionalTests.Query.GearsOfWarQueryJetTest.Where_enum_has_flag_subquery_client_eval(isAsync: True)
EntityFrameworkCore.Jet.FunctionalTests.Query.GearsOfWarQueryJetTest.Where_enum_has_flag_subquery_with_pushdown(isAsync: False)
@ -17040,6 +17044,10 @@ EntityFrameworkCore.Jet.FunctionalTests.Query.TPCGearsOfWarQueryJetTest.Where_co
EntityFrameworkCore.Jet.FunctionalTests.Query.TPCGearsOfWarQueryJetTest.Where_count_subquery_without_collision(async: True)
EntityFrameworkCore.Jet.FunctionalTests.Query.TPCGearsOfWarQueryJetTest.Where_DateOnly_DayOfWeek(async: False)
EntityFrameworkCore.Jet.FunctionalTests.Query.TPCGearsOfWarQueryJetTest.Where_DateOnly_DayOfWeek(async: True)
EntityFrameworkCore.Jet.FunctionalTests.Query.TPCGearsOfWarQueryJetTest.Where_datetimeoffset_dayofyear_component(async: False)
EntityFrameworkCore.Jet.FunctionalTests.Query.TPCGearsOfWarQueryJetTest.Where_datetimeoffset_dayofyear_component(async: True)
EntityFrameworkCore.Jet.FunctionalTests.Query.TPCGearsOfWarQueryJetTest.Where_datetimeoffset_month_component(async: False)
EntityFrameworkCore.Jet.FunctionalTests.Query.TPCGearsOfWarQueryJetTest.Where_datetimeoffset_month_component(async: True)
EntityFrameworkCore.Jet.FunctionalTests.Query.TPCGearsOfWarQueryJetTest.Where_enum_has_flag_subquery_client_eval(async: False)
EntityFrameworkCore.Jet.FunctionalTests.Query.TPCGearsOfWarQueryJetTest.Where_enum_has_flag_subquery_client_eval(async: True)
EntityFrameworkCore.Jet.FunctionalTests.Query.TPCGearsOfWarQueryJetTest.Where_enum_has_flag_subquery_with_pushdown(async: False)
@ -18634,6 +18642,10 @@ EntityFrameworkCore.Jet.FunctionalTests.Query.TPTGearsOfWarQueryJetTest.Where_co
EntityFrameworkCore.Jet.FunctionalTests.Query.TPTGearsOfWarQueryJetTest.Where_count_subquery_without_collision(async: True)
EntityFrameworkCore.Jet.FunctionalTests.Query.TPTGearsOfWarQueryJetTest.Where_DateOnly_DayOfWeek(async: False)
EntityFrameworkCore.Jet.FunctionalTests.Query.TPTGearsOfWarQueryJetTest.Where_DateOnly_DayOfWeek(async: True)
EntityFrameworkCore.Jet.FunctionalTests.Query.TPTGearsOfWarQueryJetTest.Where_datetimeoffset_dayofyear_component(async: False)
EntityFrameworkCore.Jet.FunctionalTests.Query.TPTGearsOfWarQueryJetTest.Where_datetimeoffset_dayofyear_component(async: True)
EntityFrameworkCore.Jet.FunctionalTests.Query.TPTGearsOfWarQueryJetTest.Where_datetimeoffset_month_component(async: False)
EntityFrameworkCore.Jet.FunctionalTests.Query.TPTGearsOfWarQueryJetTest.Where_datetimeoffset_month_component(async: True)
EntityFrameworkCore.Jet.FunctionalTests.Query.TPTGearsOfWarQueryJetTest.Where_enum_has_flag_subquery_client_eval(async: False)
EntityFrameworkCore.Jet.FunctionalTests.Query.TPTGearsOfWarQueryJetTest.Where_enum_has_flag_subquery_client_eval(async: True)
EntityFrameworkCore.Jet.FunctionalTests.Query.TPTGearsOfWarQueryJetTest.Where_enum_has_flag_subquery_with_pushdown(async: False)

@ -26,5 +26,17 @@ namespace EntityFrameworkCore.Jet.FunctionalTests.Query
base.Seed(context);
}
public override ISetSource GetExpectedData()
{
var data = (GearsOfWarData)base.GetExpectedData();
foreach (var mission in data.Missions)
{
mission.Timeline = JetTestHelpers.GetExpectedValue(mission.Timeline);
}
return data;
}
}
}

@ -2563,9 +2563,11 @@ WHERE DATEPART('yyyy', `m`.`Timeline`) = 2");
await base.Where_datetimeoffset_month_component(isAsync);
AssertSql(
$@"SELECT `m`.`Id`, `m`.`CodeName`, `m`.`Rating`, `m`.`Timeline`
"""
SELECT `m`.`Id`, `m`.`CodeName`, `m`.`Date`, `m`.`Duration`, `m`.`Rating`, `m`.`Time`, `m`.`Timeline`
FROM `Missions` AS `m`
WHERE DATEPART('m', `m`.`Timeline`) = 1");
WHERE DATEPART('m', `m`.`Timeline`) = 1
""");
}
public override async Task Where_datetimeoffset_dayofyear_component(bool isAsync)
@ -2573,9 +2575,11 @@ WHERE DATEPART('m', `m`.`Timeline`) = 1");
await base.Where_datetimeoffset_dayofyear_component(isAsync);
AssertSql(
$@"SELECT `m`.`Id`, `m`.`CodeName`, `m`.`Rating`, `m`.`Timeline`
"""
SELECT `m`.`Id`, `m`.`CodeName`, `m`.`Date`, `m`.`Duration`, `m`.`Rating`, `m`.`Time`, `m`.`Timeline`
FROM `Missions` AS `m`
WHERE DATEPART(dayofyear, `m`.`Timeline`) = 2");
WHERE DATEPART('y', `m`.`Timeline`) = 2
""");
}
public override async Task Where_datetimeoffset_day_component(bool isAsync)

@ -10321,7 +10321,7 @@ WHERE `e`.`DateTime` = CDATE(@__parameter_0)
AssertSql(
"""
@__parameter_0='2021-11-12T13:14:15.0000000' (DbType = DateTime)
@__parameter_0='2021-11-12T03:14:15.0000000Z' (DbType = DateTime)
SELECT TOP 1 `e`.`DateTimeOffset`
FROM `Entities` AS `e`

@ -28,4 +28,16 @@ public class TPCGearsOfWarQueryJetFixture : TPCGearsOfWarQueryRelationalFixture
base.Seed(context);
}
public override ISetSource GetExpectedData()
{
var data = (GearsOfWarData)base.GetExpectedData();
foreach (var mission in data.Missions)
{
mission.Timeline = JetTestHelpers.GetExpectedValue(mission.Timeline);
}
return data;
}
}

@ -3738,10 +3738,10 @@ WHERE DATEPART(year, [m].[Timeline]) = 2
await base.Where_datetimeoffset_month_component(async);
AssertSql(
"""
SELECT [m].[Id], [m].[CodeName], [m].[Duration], [m].[Rating], [m].[Timeline]
FROM [Missions] AS [m]
WHERE DATEPART(month, [m].[Timeline]) = 1
"""
SELECT `m`.`Id`, `m`.`CodeName`, `m`.`Date`, `m`.`Duration`, `m`.`Rating`, `m`.`Time`, `m`.`Timeline`
FROM `Missions` AS `m`
WHERE DATEPART('m', `m`.`Timeline`) = 1
""");
}
@ -3750,10 +3750,10 @@ WHERE DATEPART(month, [m].[Timeline]) = 1
await base.Where_datetimeoffset_dayofyear_component(async);
AssertSql(
"""
SELECT [m].[Id], [m].[CodeName], [m].[Duration], [m].[Rating], [m].[Timeline]
FROM [Missions] AS [m]
WHERE DATEPART(dayofyear, [m].[Timeline]) = 2
"""
SELECT `m`.`Id`, `m`.`CodeName`, `m`.`Date`, `m`.`Duration`, `m`.`Rating`, `m`.`Time`, `m`.`Timeline`
FROM `Missions` AS `m`
WHERE DATEPART('y', `m`.`Timeline`) = 2
""");
}

@ -28,4 +28,16 @@ public class TPTGearsOfWarQueryJetFixture : TPTGearsOfWarQueryRelationalFixture
base.Seed(context);
}
public override ISetSource GetExpectedData()
{
var data = (GearsOfWarData)base.GetExpectedData();
foreach (var mission in data.Missions)
{
mission.Timeline = JetTestHelpers.GetExpectedValue(mission.Timeline);
}
return data;
}
}

@ -2989,10 +2989,10 @@ WHERE DATEPART(year, [m].[Timeline]) = 2
await base.Where_datetimeoffset_month_component(async);
AssertSql(
"""
SELECT [m].[Id], [m].[CodeName], [m].[Duration], [m].[Rating], [m].[Timeline]
FROM [Missions] AS [m]
WHERE DATEPART(month, [m].[Timeline]) = 1
"""
SELECT `m`.`Id`, `m`.`CodeName`, `m`.`Date`, `m`.`Duration`, `m`.`Rating`, `m`.`Time`, `m`.`Timeline`
FROM `Missions` AS `m`
WHERE DATEPART('m', `m`.`Timeline`) = 1
""");
}
@ -3001,10 +3001,10 @@ WHERE DATEPART(month, [m].[Timeline]) = 1
await base.Where_datetimeoffset_dayofyear_component(async);
AssertSql(
"""
SELECT [m].[Id], [m].[CodeName], [m].[Duration], [m].[Rating], [m].[Timeline]
FROM [Missions] AS [m]
WHERE DATEPART(dayofyear, [m].[Timeline]) = 2
"""
SELECT `m`.`Id`, `m`.`CodeName`, `m`.`Date`, `m`.`Duration`, `m`.`Rating`, `m`.`Time`, `m`.`Timeline`
FROM `Missions` AS `m`
WHERE DATEPART('y', `m`.`Timeline`) = 2
""");
}

@ -6,6 +6,7 @@ using EntityFrameworkCore.Jet.Diagnostics.Internal;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.TestUtilities;
using Microsoft.Extensions.DependencyInjection;
using System;
namespace EntityFrameworkCore.Jet.FunctionalTests.TestUtilities
{
@ -26,5 +27,11 @@ namespace EntityFrameworkCore.Jet.FunctionalTests.TestUtilities
public override LoggingDefinitions LoggingDefinitions { get; } = new JetLoggingDefinitions();
public string GetStoreName(string storeNameWithoutSuffix) => $"{storeNameWithoutSuffix}.accdb";
public static DateTimeOffset GetExpectedValue(DateTimeOffset value)
{
var val = value.UtcDateTime;
return new DateTimeOffset(new DateTime(val.Year, val.Month, val.Day, val.Hour, val.Minute, val.Second), TimeSpan.Zero);
}
}
}

Loading…
Cancel
Save