C# 使用SQL或LINQ to SQL按月份分组、按时区调整记录计数的最佳方法
我正在寻找一种最有效的方法来提取数据库中的一系列月度记录,但要根据时区进行调整,因为时间实际上存储为UTC。我希望我的结果集是一系列对象,包括月份、年份和计数 我有LINQ到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
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服务器时区支持”所述