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

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

@ -37,7 +37,7 @@ namespace EntityFrameworkCore.Jet.Storage.Internal
// OLE DB can't handle the DateTimeOffset type. // OLE DB can't handle the DateTimeOffset type.
if (parameter.Value is DateTimeOffset dateTimeOffset) if (parameter.Value is DateTimeOffset dateTimeOffset)
{ {
parameter.Value = dateTimeOffset.DateTime; parameter.Value = dateTimeOffset.UtcDateTime;
parameter.DbType = System.Data.DbType.DateTime; parameter.DbType = System.Data.DbType.DateTime;
} }
@ -50,7 +50,7 @@ namespace EntityFrameworkCore.Jet.Storage.Internal
protected override string GenerateNonNullSqlLiteral(object value) protected override string GenerateNonNullSqlLiteral(object value)
{ {
if (value is not DateTimeOffset offset) return base.GenerateNonNullSqlLiteral(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); 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_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: False)
EntityFrameworkCore.Jet.FunctionalTests.Query.GearsOfWarQueryJetTest.Where_DateOnly_DayOfWeek(async: True) 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: 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_client_eval(isAsync: True)
EntityFrameworkCore.Jet.FunctionalTests.Query.GearsOfWarQueryJetTest.Where_enum_has_flag_subquery_with_pushdown(isAsync: False) 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_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: False)
EntityFrameworkCore.Jet.FunctionalTests.Query.TPCGearsOfWarQueryJetTest.Where_DateOnly_DayOfWeek(async: True) 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: 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_client_eval(async: True)
EntityFrameworkCore.Jet.FunctionalTests.Query.TPCGearsOfWarQueryJetTest.Where_enum_has_flag_subquery_with_pushdown(async: False) 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_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: False)
EntityFrameworkCore.Jet.FunctionalTests.Query.TPTGearsOfWarQueryJetTest.Where_DateOnly_DayOfWeek(async: True) 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: 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_client_eval(async: True)
EntityFrameworkCore.Jet.FunctionalTests.Query.TPTGearsOfWarQueryJetTest.Where_enum_has_flag_subquery_with_pushdown(async: False) 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); 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); await base.Where_datetimeoffset_month_component(isAsync);
AssertSql( 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` 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) 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); await base.Where_datetimeoffset_dayofyear_component(isAsync);
AssertSql( 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` 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) public override async Task Where_datetimeoffset_day_component(bool isAsync)

@ -10321,7 +10321,7 @@ WHERE `e`.`DateTime` = CDATE(@__parameter_0)
AssertSql( 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` SELECT TOP 1 `e`.`DateTimeOffset`
FROM `Entities` AS `e` FROM `Entities` AS `e`

@ -28,4 +28,16 @@ public class TPCGearsOfWarQueryJetFixture : TPCGearsOfWarQueryRelationalFixture
base.Seed(context); 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;
}
} }

@ -3739,9 +3739,9 @@ WHERE DATEPART(year, [m].[Timeline]) = 2
AssertSql( AssertSql(
""" """
SELECT [m].[Id], [m].[CodeName], [m].[Duration], [m].[Rating], [m].[Timeline] SELECT `m`.`Id`, `m`.`CodeName`, `m`.`Date`, `m`.`Duration`, `m`.`Rating`, `m`.`Time`, `m`.`Timeline`
FROM [Missions] AS [m] FROM `Missions` AS `m`
WHERE DATEPART(month, [m].[Timeline]) = 1 WHERE DATEPART('m', `m`.`Timeline`) = 1
"""); """);
} }
@ -3751,9 +3751,9 @@ WHERE DATEPART(month, [m].[Timeline]) = 1
AssertSql( AssertSql(
""" """
SELECT [m].[Id], [m].[CodeName], [m].[Duration], [m].[Rating], [m].[Timeline] SELECT `m`.`Id`, `m`.`CodeName`, `m`.`Date`, `m`.`Duration`, `m`.`Rating`, `m`.`Time`, `m`.`Timeline`
FROM [Missions] AS [m] FROM `Missions` AS `m`
WHERE DATEPART(dayofyear, [m].[Timeline]) = 2 WHERE DATEPART('y', `m`.`Timeline`) = 2
"""); """);
} }

@ -28,4 +28,16 @@ public class TPTGearsOfWarQueryJetFixture : TPTGearsOfWarQueryRelationalFixture
base.Seed(context); 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;
}
} }

@ -2990,9 +2990,9 @@ WHERE DATEPART(year, [m].[Timeline]) = 2
AssertSql( AssertSql(
""" """
SELECT [m].[Id], [m].[CodeName], [m].[Duration], [m].[Rating], [m].[Timeline] SELECT `m`.`Id`, `m`.`CodeName`, `m`.`Date`, `m`.`Duration`, `m`.`Rating`, `m`.`Time`, `m`.`Timeline`
FROM [Missions] AS [m] FROM `Missions` AS `m`
WHERE DATEPART(month, [m].[Timeline]) = 1 WHERE DATEPART('m', `m`.`Timeline`) = 1
"""); """);
} }
@ -3002,9 +3002,9 @@ WHERE DATEPART(month, [m].[Timeline]) = 1
AssertSql( AssertSql(
""" """
SELECT [m].[Id], [m].[CodeName], [m].[Duration], [m].[Rating], [m].[Timeline] SELECT `m`.`Id`, `m`.`CodeName`, `m`.`Date`, `m`.`Duration`, `m`.`Rating`, `m`.`Time`, `m`.`Timeline`
FROM [Missions] AS [m] FROM `Missions` AS `m`
WHERE DATEPART(dayofyear, [m].[Timeline]) = 2 WHERE DATEPART('y', `m`.`Timeline`) = 2
"""); """);
} }

@ -6,6 +6,7 @@ using EntityFrameworkCore.Jet.Diagnostics.Internal;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.TestUtilities; using Microsoft.EntityFrameworkCore.TestUtilities;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using System;
namespace EntityFrameworkCore.Jet.FunctionalTests.TestUtilities namespace EntityFrameworkCore.Jet.FunctionalTests.TestUtilities
{ {
@ -26,5 +27,11 @@ namespace EntityFrameworkCore.Jet.FunctionalTests.TestUtilities
public override LoggingDefinitions LoggingDefinitions { get; } = new JetLoggingDefinitions(); public override LoggingDefinitions LoggingDefinitions { get; } = new JetLoggingDefinitions();
public string GetStoreName(string storeNameWithoutSuffix) => $"{storeNameWithoutSuffix}.accdb"; 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