2011-10-28 58 views
1

我有以下代碼:LINQ的GroupBy DateTime的困境

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

此代碼工作得很好,但問題是,日期時間存儲在數據庫中的UTC。在我執行GroupBy操作的那一刻,我失去了時間部分。所以,如果我試圖把它與以下轉換回LOCA時間:

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

這將是基於不同的時間,因此不正確。該列必須保留DateTime。

有什麼建議嗎?

+0

你真的不清楚你想做什麼......你是否試圖根據運行.NET的服務器的本地時間對UTC存儲的日期進行分組?說實話,這聽起來不太可能是個好主意。 –

+0

由於我在數據庫中存儲了所有UTC,因此我想顯示按日期分組的用戶數,但日期應該在當地時間。原因在於,如果用戶在美國東部時間10/28 9pm報名,他實際上在格林威治標準時間上午10點29分簽了名。目前的代碼將該數字歸因於每個人的第29位。我試圖完成的是東部時間的用戶將該用戶歸因於第28位。我有什麼意義嗎? – Thomas

+0

但是這是在討論*用戶的*時區,而不是服務器的時區。如果你在不同的時區使它工作,那麼不同的人會得到不同的結果,這聽起來不太好。如果您對何時在當地時間註冊的人感興趣,則應將其存儲在當地時間而不是UTC中。 –

回答

0

聽起來真正的挑戰是你需要翻譯兩次。首先,需要將用於輸入方法的本地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); 
} 

此時,字典對象中的日期值已經在本地時間,因此不需要將它們轉換爲表示形式。