LINQ GroupBy DateTime 困境

发布于 2024-12-12 05:50:07 字数 834 浏览 0 评论 0原文

我有以下代码:

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 操作时,我失去了时间部分。因此,如果我尝试使用以下命令将其转换回本地时间:

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

它将基于不同的时间,因此不正确。该列必须保留日期时间。

有什么建议吗?

I have the following code:

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);
}

This code works perfectly well but the problem is that the DateTime is stored as UTC in the database. The moment I do the GroupBy operation I lose the Time part. So if I tried to convert it back to loca time with the following:

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

It would be based on a different time and therefore incorrect. The column has to stay DateTime.

Any suggestions?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

來不及說愛妳 2024-12-19 05:50:07

听起来真正的挑战是您需要翻译两次。首先,将您输入到方法中的本地日期时间(只有在本地的情况下您的问题才有意义)需要转换为 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); 
} 

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

It sounds like the real challenge is that you'll need to translate twice. First, taking the local DateTime you're feeding into the method (your question only makes sense if those are local) need to be translated into UTC for the query. But then you need to translate x.CreatedAt into local before you do your grouping—on the server, in other words. This is tricky, but works if you use the SqlFunctions library in System.Data.Objects.SqlClient. Here's what it'd look like. Messy and I don't know how performant it'd be, but it should work.

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); 
} 

At that point, the date values in your dictionary object are already in local time, so no need to convert them for presentation.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文