如何在实体框架中将 datetimeoffset 转换为 datetime?

问题描述 投票:0回答:3

这似乎是一件简单的事情,但 EF 不支持像

DateTimeOffset.DateTime
DateTimeOffset.LocalDateTime
甚至
DateTime.Date
这样的属性。 我试图仅通过 DateTime 组件(即“本地”DateTime)过滤 DateTimeOffset 类型字段,这在普通 sql 中是一件简单的事情:
where cast(x as datetime) = '2016-12-14'

有一个

DbFunctions.TruncateTime
,但没有对应的
TruncateOffset

似乎没有任何方法可以将

DateTimeOffset
对象转换或转换为在 linq-to-entities 中工作的普通
DateTime
对象。唯一的转换是从
DateTime
DateTimeOffset
的隐式转换,但反之则不然。

entity-framework-6 datetimeoffset
3个回答
2
投票

您可以使用 DbFunctions.CreateDateTime 来去除偏移量,例如:

...
.Select(e => new MyClass {                                      
  MyDate = DbFunctions.CreateDateTime(e.MyDateTimeOffset.Year,
                                      e.MyDateTimeOffset.Month,
                                      e.MyDateTimeOffset.Day,
                                      e.MyDateTimeOffset.Hour,
                                      e.MyDateTimeOffset.Minute,
                                      e.MyDateTimeOffset.Second)
...

正如您可能怀疑的那样,这会创建一些真正糟糕的 SQL,即:

convert (datetime2,right('000' + convert(varchar(255), DATEPART (year, [Extent1].[MyDateTimeOffset])), 4) + '-' + convert(varchar(255), DATEPART (month, [Extent1].[MyDateTimeOffset])) + '-' + convert(varchar(255), DATEPART (day, [Extent1].[MyDateTimeOffset])) + ' ' + convert(varchar(255), DATEPART (hour, [Extent1].[MyDateTimeOffset])) + ':' + convert(varchar(255), DATEPART (minute, [Extent1].[MyDateTimeOffset])) + ':' + str( CAST( DATEPART (second, [Extent1].[MyDateTimeOffset]) AS float), 10, 7), 121) AS [C2]

但是它会给你你想要的。

需要注意的是,这将完全剥离/忽略偏移(按照OP的要求)。


0
投票

我遇到了与

DbFunctions.TruncateTime
完全相同的问题,并且能够使用
DbFunctions.DiffDays

解决它

这是一个例子:

DbFunctions.DiffDays(DateTimeOffset.Now, x.EventDate) == 0

使用 DbFunctions.DiffDays 时,不考虑偏移量。以下是 MSDN 文档:https://msdn.microsoft.com/en-us/library/dn220092(v=vs.113).aspx


0
投票

在 EF Core 中,您可以使用

DbFunctions
类。考虑以下几点:

var query = await DbContext.Records
    .AsNoTracking()
    .OrderByDescending(x => x.Date)
    .Where(x => EF.Functions.DateFromParts(x.Date.Year, x.Date.Month, x.Date.Day) >= startDate)
    .ToListAsync();

请注意,如果您的日期列是

DateTimeOffset
,您可能需要在查询数据库后在客户端转换这些值,例如将它们转换为本地日期和时间。

另一个有用的功能是对值进行分区。如果您将日期作为 UTC 存储在数据库中,使用

DatimeTimeOffset
列(正如您应该的那样),如何针对不同时区查询数据库?

您可以使用

AtTimeZone
方法。考虑以下示例,我们按日期对记录进行分组,并划分到特定时区:

var query = await DbContext.Records
    .AsNoTracking()
    .OrderByDescending(x => x.Date)
    .GroupBy(x => EF.Functions.DateFromParts(
        EF.Functions.AtTimeZone(x.Date, TIME_ZONE_ID).Year,
        EF.Functions.AtTimeZone(x.Date, TIME_ZONE_ID).Month,
        EF.Functions.AtTimeZone(x.Date, TIME_ZONE_ID).Day))
    .OrderByDescending(x => x.Key)
    .Select(x => new 
    {
        Date = x.Key,
        Records = x.ToList()
    })
    .ToListAsync();

TIME_ZONE_ID
是有效的时区标识符(例如
Iran Standard Time
)。您可以将任何参数应用于此类查询,并实现分页。但请注意,像这样分组时,您可能无法使用查询拆分,因为它可能会抛出异常,表明您的查询无法转换为 SQL。

© www.soinside.com 2019 - 2024. All rights reserved.