我正在尝试编写一个 EF6 LINQ 查询,该查询采用 DateTimeOffset 并检索时间戳与给定本地日期相同的所有数据库条目。数据库的所有时间戳均为 UTC,但 DateTimeOffset 参数包含与 UTC 的本地偏移量,作为“同一天”标识的基础。
例如,假设数据库有两个时间戳分别为“2024-09-01 4PM UTC+0”和“2024-09-02 5AM UTC+0”的条目。
如果我传入的 DateTimeOffset 为“2024-09-01 11AM UTC-7”,我希望两个条目匹配:“2024-09-01 4PM UTC+0”转换为“2024-09-01 9AM UTC” -7”和“2024-09-02 5AM UTC+0”转换为“2024-09-01 10PM UTC-7”,并且两个结果的日期都与参数的日期 2024-09-01 匹配。
如果我传入“2024-08-31 9PM UTC-7”的 DateTimeOffset,则应该没有匹配项,因为将数据库时间戳转换为 UTC-7 会产生落在“2024-09-1”而不是“2024- 08-31”。请注意,此处给定的时间戳转换为“2024-09-01 4AM UTC+0”,但没有匹配项,因为本地偏移量作为基础 - 而不是 UTC。
最后,给出“2024-09-02 3AM UTC+1”的 DateTimeOffset 应该仅与时间戳为“2024-09-02 5AM UTC+0”的数据库条目匹配,因为该时间戳会转换为“2024-09-02” 6AM UTC+1”,具有匹配的 2024-09-02 日期,但“2024-09-01 4PM UTC+0”的条目转换为“2024-09-01 5PM UTC+1”并且不匹配。
像上面那样布局将使编写一个 C# 函数看起来很简单,该函数可以根据给定的 DateTimeOffset 和时间戳列表查找匹配项。但是,如果可能的话,我希望在数据库上进行所有处理,以利用索引并最大限度地减少检索的行数(即仅获取通过检查的条目)。
因此,我不能使用类似的东西:
return context.Table.Where(row => row.Timestamp.ToOffset(givenDTO.Offset).Date == givenDTO.Date).ToList();
因为 LINQ to Entities 不支持
ToOffset()
和 Date
。
我尝试过使用System.Data.Entity.DbFunctions,但是我找不到很多使用示例,所以我的结果都是错误的或者抛出异常。例如:
return context.Table.Where(row => DbFunctions.DiffDays(row.Timestamp, givenDTO) <= 1).ToList()
在给出“2024-08-31 9PM UTC-7”的第二种情况下失败。
尝试通过
DbFunctions.CreateDateTimeOffset()
为每个条目创建一个新的 DateTimeOffset 来与给定的 DateTimeOffset 进行比较,如果给定的 DateTimeOffset 的偏移量为负数,则为 givenDTO.Offset.Hours
参数传递 int? timeZoneOffset
会产生 OverflowException。
我不知道如何编写这个查询。还可能吗?
您是否可以将本地参考时间转换为 UTC 日期/时间范围,然后在查询中用作过滤器,而不是将数据库
Timestamp
值转换为本地时间进行比较?
类似:
DataTime fromUtc = givenDTO.Date - givenDTO.Date.Offset; // Not sure of the exact expression
DataTime toUtc = fromUtc.AddDays(1);
return context.Table
.Where(row => row.Timestamp >= fromUtc && row.Timestamp < toUtc)
.ToList();
例如,给定日期时间偏移量
2024-08-09 12:34 +0200
,我们将截断日期并调整为 UTC,产生 fromUtc = 2024-08-08 22:00
,然后为 toUtc = 2024-08-09 22:00
添加 24 小时。然后我们查询具有 Timestamp >= '2024-08-08 22:00' && Timestamp < '2024-08-09 22:00'
的行。
请注意,
toUtc
是排他性。匹配值不包含在结果中。