C# 使用SQL或LINQ to SQL按月份分组、按时区调整记录计数的最佳方法

C# 使用SQL或LINQ to SQL按月份分组、按时区调整记录计数的最佳方法,c#,.net,sql-server,linq-to-sql,C#,.net,Sql Server,Linq To Sql,我正在寻找一种最有效的方法来提取数据库中的一系列月度记录,但要根据时区进行调整,因为时间实际上存储为UTC。我希望我的结果集是一系列对象,包括月份、年份和计数 我有LINQ到SQL对象,看起来像这样: public class MyRecord { public int ID { get; set; } public DateTime TimeStamp { get; set; } public string Data { get; set; } } 我并不反对使用直接SQL

我正在寻找一种最有效的方法来提取数据库中的一系列月度记录,但要根据时区进行调整,因为时间实际上存储为UTC。我希望我的结果集是一系列对象,包括月份、年份和计数

我有LINQ到SQL对象,看起来像这样:

public class MyRecord {
   public int ID { get; set; }
   public DateTime TimeStamp { get; set; }
   public string Data { get; set; }
}
我并不反对使用直接SQL,但LINQtoSQL至少可以让代码更干净。时区调整可用作整数(-5,例如)。同样,我要查找的结果集是包含月份、年份和计数的对象,所有整数

有什么建议吗?我可以想出几种直接的方法,但不是通过时区调整

编辑:下面的答案让我朝着正确的方向前进。这就是我最终的结局:

var counts = _context.MyRecord
    .Select(r => new {original = r.TimeStamp, adjusted = TimeAdjust.GetAdjustedTime(Config.TimeZoneAdjustment, r.TimeStamp)}).ToArray()
    .GroupBy(r => new {r.adjusted.Month, r.adjusted.Year})
    .Select(g => new MonthCount { Count = g.Count(), Year = g.Key.Year, Month = g.Key.Month })
    .OrderByDescending(g => g.Year).ThenByDescending(g => g.Month);
基本上,我把所有的日期都拉下来了,考虑到这个应用程序的范围有限,这样做还行。TimeAdjust函数获取“实际”调整时间,计算DLS。调用ToArray()是为了避免由于时间调整函数而导致SQL延迟执行

context.MyRecords

    // tz adjusted, projection
   .Select(r => new {original = r.TimeStamp, adjusted = r.TimeStamp.AddHours(tz)})

   // group by start of month
   .GroupBy (r => r.adjusted.Date.AddDays(-r.Day))

   // final projection from groups to values asked for
   .Select (g => new {count = g.Count(), year = g.Key.Year, month = g.Key.Month})
注:正如@dana指出的,如果你也想考虑夏令时,这就要复杂得多。按偏移时间分组忽略DST对于大多数报告将得到足够好的答案,因为唯一会被错误计算的值是在月份边界上,在一年中的几个月里大约是午夜

如果您确实想考虑DST,那么它比查看日期范围和添加额外的一小时要复杂得多。从历史上看,时区的边界和偏移量都发生了变化,因此要做到这一点,您需要这些变化的历史记录,并且需要知道用户的位置。一个简单的TZ偏移量并不能解决这个问题

如果你计算DST,你还需要确保你不会损失一个小时或一年两次重复计算一个小时


如果您考虑DST,几乎不可能100%正确地实现这一点,这就是为什么只有TZ偏移量的方法是更好的选择。

如果您使用的是MySql,那么您可以使用以下函数:

转换_-TZ(dt,从_-TZ到_-TZ)

  • 将日期时间值dt从from_tz给定的时区转换为to_tz给定的时区,并返回结果值。时区的指定如第9.7节“MySQL服务器时区支持”所述

顺便说一句,时区偏移量不应为整数小时-存在分数时区。请注意,这是供我们使用的。不幸的是,生成的SQL进行了大量嵌套转换,并涉及毫秒。这会引发一个错误,即:“数据类型date的date函数dateadd不支持datepart毫秒。”这实际上是一个通配符查询(在探查器中查看)。是否可以选择移动到Entity Framework 4?MSFT确实增强了EF4中的日期时间函数。它可能比现在的L2S更好地处理这个问题(还没有检查)。另见。。。如果可以的话,我真的很想避免使用EF,因为这个小应用程序会被一些年轻人使用,他们会对附加的依赖项感到抓狂。你可以尝试将它转换为TimeSpan ys并使用(t.TimeStamp+ts)??有一个应该工作的列表。我会将此标记为答案,但我在编辑中使用了代码。没有用,因为问题不是关于MySql的。