【问题标题】:LINQ GroupBy DateTime dilemmaLINQ GroupBy DateTime 困境
【发布时间】:2011-10-28 21:04:20
【问题描述】:

我有以下代码:

public IDictionary<string, int> GetCountByDate(DateTime fromDate, DateTime toDate)
{
    var result = Database.Set<User>().Where(x => x.CreatedAt >= fromDate && x.CreatedAt <= toDate).GroupBy(x => new { x.CreatedAt.Year, x.CreatedAt.Month, x.CreatedAt.Day }).Select(x => new { Date = x.Key, Count = x.Count() });

    return result.ToDictionary(x => new DateTime(x.Date.Year, x.Date.Month, x.Date.Day).ToShortDateString(), x => x.Count);
}

此代码运行良好,但问题是 DateTime 在数据库中存储为 UTC。在我执行 GroupBy 操作的那一刻,我失去了 Time 部分。因此,如果我尝试使用以下命令将其转换回本地时间:

return result.ToDictionary(x => new DateTime(x.Date.Year, x.Date.Month, x.Date.Day).ToLocalTime().ToShortDateString(), x => x.Count);

这将基于不同的时间,因此不正确。该列必须保持 DateTime。

有什么建议吗?

【问题讨论】:

  • 不清楚您要做什么...您是否要根据运行 .NET 的服务器的本地时间对 UTC 存储的日期进行分组?老实说,这听起来不太可能是个好主意。
  • 由于我将所有内容都作为 UTC 存储在数据库中,我想显示按日期分组的用户计数,但日期应该是本地时间。原因是如果用户在美国东部时间 10 月 28 日晚上 9 点注册,他实际上是在格林威治标准时间 10 月 29 日凌晨 2 点注册的。当前代码会将每个人的计数归因于第 29 次。我想要完成的是东部时间的用户会看到该用户归因于 28 日。我说得有道理吗?
  • 但这是关于用户的时区,而不是服务器的时区。如果你确实让它在不同的时区工作,那么不同的人会得到不同的结果,这听起来也不是很好。如果您对人们在他们的当地时间注册的时间感兴趣,那么您应该将其存储在他们的当地时间而不是UTC。
  • 乔恩,对不起我的错误。你第一次是对的。我正在尝试根据服务器的本地时间对 UTC 存储的日期进行分组。这是一个坏主意吗?如果有,为什么?
  • 服务器的本地时间很少有用值得关注。我为什么要关心服务器在哪里呢?我选择托管服务的地方有什么与业务相关的含义?

标签: linq ef-code-first


【解决方案1】:

听起来真正的挑战是您需要翻译两次。首先,需要将您输入方法的本地 DateTime (您的问题仅在本地的情况下才有意义)需要转换为 UTC 以进行查询。但是,在进行分组之前,您需要将 x.CreatedAt 翻译成本地 - 换句话说,在服务器上。这很棘手,但如果您使用 System.Data.Objects.SqlClient 中的 SqlFunctions 库,则可以。这就是它的样子。凌乱,我不知道它的性能如何,但它应该可以工作。

public IDictionary<string, int> GetCountByDate(DateTime fromDate, DateTime toDate) 
{ 
    DateTime utcFrom = fromDate.ToUniversalTime();
    DateTime utcTo = toDate.ToUniversalTime();
    int offset = (int)(fromDate - utcFrom).TotalHours;
    var result = Database.Set<User>().Where(x => x.CreatedAt >= utcFrom && x.CreatedAt <= utcTo)
        .GroupBy(x => new { 
            SqlFunctions.DateAdd("hh", offset, x.CreatedAt).Value.Year, 
            SqlFunctions.DateAdd("hh", offset, x.CreatedAt).Value.Month, 
            SqlFunctions.DateAdd("hh", offset, x.CreatedAt).Value.Day })
        .Select(x => new { Date = x.Key, Count = x.Count() });

    return result.ToDictionary(x => new DateTime(x.Date.Year, x.Date.Month, x.Date.Day).ToShortDateString(), x => x.Count); 
} 

此时,您的字典对象中的日期值已经是本地时间,因此无需转换它们以进行展示。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-10-01
    • 1970-01-01
    • 1970-01-01
    • 2015-06-03
    • 2013-04-23
    • 1970-01-01
    • 1970-01-01
    • 2012-06-24
    相关资源
    最近更新 更多