Лучший способ получить количество записей, сгруппированных по месяцам, с поправкой на часовой пояс, используя SQL или LINQ to SQL - PullRequest
1 голос
/ 16 апреля 2010

Я ищу наиболее эффективный способ отсосать серию ежемесячных подсчетов записей в моей базе данных, но с учетом часового пояса, поскольку время фактически сохраняется как UTC. Мне бы хотелось, чтобы мой набор результатов представлял собой серию объектов, включающую месяц, год и число.

У меня есть объекты LINQ to SQL, которые выглядят примерно так:

public class MyRecord {
   public int ID { get; set; }
   public DateTime TimeStamp { get; set; }
   public string Data { get; set; }
}

Я не против использования прямого SQL, но LINQ to SQL, по крайней мере, сделает код намного более чистым. Настройка часового пояса доступна в виде целого числа (например, -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-кода из-за функции корректировки времени.

Ответы [ 2 ]

1 голос
/ 16 апреля 2010
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 даст достаточно хороший ответ для большинства отчетов, поскольку единственные значения, которые будут ошибочно учтены, находятся на границах месяца, около полуночи в течение нескольких месяцев года.

Если вы хотите учесть летнее время, это сложнее, чем просто смотреть на диапазон дат и добавлять дополнительный час. Исторически как границы, так и смещения часовых поясов менялись, поэтому, чтобы сделать это правильно, вам нужна историческая запись об этих изменениях, и вам нужно знать местоположение пользователя. Простое смещение TZ не дает вам этого.

ЕСЛИ вы учитываете DST, вам также необходимо убедиться, что вы не теряете час и не учитываете дважды счет дважды в год.

Почти невозможно получить эти 100% правильные ставки, если вы учитываете DST, поэтому подход с использованием только TZ-смещения - лучшая ставка.

0 голосов
/ 16 апреля 2010

Если бы вы использовали MySql, то вы могли бы использовать функцию:

CONVERT_TZ (dt, from_tz, to_tz)

  • преобразовывает значение даты / времени dt из часового пояса, заданногоfrom_tz в часовой пояс, заданный to_tz и возвращает результирующее значение.Часовые пояса определяются, как описано в Разделе 9.7, «Поддержка часовых поясов MySQL Server»
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...