2011-04-15 69 views
6

我在數據庫中的日期時間,我使用實體框架的數據庫中檢索的話,我再通過DataContractJsonSerializer傳遞出通過JSON API的數據。DataContractJsonSerializer DateTime的隱式時區轉換

在日期時間字段的時間顯示根據服務器的本地時區而在DataContractJsonSerializer被加工進行了調整。時間表示時間比預期時間提前1小時。 DateTime類型是UTC,但以前它是未指定的,並且我有同樣的問題。

在我的應用程序,我想明確地時區,並在客戶端,而不是服務器之間進行轉換,因爲這更有意義。我對這個隱式功能感到驚訝,因爲我的日期時間值應該像整數一樣是簡單的值。

感謝

回答

4

DataContractJsonSerializer將輸出時區部分(+ ZZZZ),如果你的DateTime.Kind等於本地或未指定。這種行爲不同於XmlSerializer,如果Kind等於Unspecified,它只輸出時區部分。

如果好奇退房的源JsonWriterDelegator其中包含以下方法:

internal override void WriteDateTime(DateTime value) 
    { 
     // ToUniversalTime() truncates dates to DateTime.MaxValue or DateTime.MinValue instead of throwing 
     // This will break round-tripping of these dates (see bug 9690 in CSD Developer Framework) 
     if (value.Kind != DateTimeKind.Utc) 
     { 
      long tickCount = value.Ticks - TimeZone.CurrentTimeZone.GetUtcOffset(value).Ticks; 
      if ((tickCount > DateTime.MaxValue.Ticks) || (tickCount < DateTime.MinValue.Ticks)) 
      { 
       throw DiagnosticUtility.ExceptionUtility.ThrowHelperError( 
        XmlObjectSerializer.CreateSerializationException(SR.GetString(SR.JsonDateTimeOutOfRange), new ArgumentOutOfRangeException("value"))); 
      } 
     } 

     writer.WriteString(JsonGlobals.DateTimeStartGuardReader); 
     writer.WriteValue((value.ToUniversalTime().Ticks - JsonGlobals.unixEpochTicks)/10000); 

     switch (value.Kind) 
     { 
      case DateTimeKind.Unspecified: 
      case DateTimeKind.Local: 
       // +"zzzz"; 
       TimeSpan ts = TimeZone.CurrentTimeZone.GetUtcOffset(value.ToLocalTime()); 
       if (ts.Ticks < 0) 
       { 
        writer.WriteString("-"); 
       } 
       else 
       { 
        writer.WriteString("+"); 
       } 
       int hours = Math.Abs(ts.Hours); 
       writer.WriteString((hours < 10) ? "0" + hours : hours.ToString(CultureInfo.InvariantCulture)); 
       int minutes = Math.Abs(ts.Minutes); 
       writer.WriteString((minutes < 10) ? "0" + minutes : minutes.ToString(CultureInfo.InvariantCulture)); 
       break; 
      case DateTimeKind.Utc: 
       break; 
     } 
     writer.WriteString(JsonGlobals.DateTimeEndGuardReader); 
    } 

我已經在我的機器

var jsonSerializer = new DataContractJsonSerializer(typeof(DateTime)); 
var date = DateTime.UtcNow; 
     Console.WriteLine("original date = " + date.ToString("s")); 
     using (var stream = new MemoryStream()) 
     { 
      jsonSerializer.WriteObject(stream, date); 

      stream.Position = 0; 
      var deserializedDate = (DateTime)jsonSerializer.ReadObject(stream); 
      Console.WriteLine("deserialized date = " + deserializedDate.ToString("s")); 

     } 

產生預期的輸出上運行以下測試:

original date = 2011-04-19T10:24:39 
deserialized date = 2011-04-19T10:24:39 

因此在某些時候你的日期必須未指定或羅CAL。

將其拉出DB後致電

entity.Date = DateTime.SpecifyKind(entity.Date, DateTimeKind.Utc); 

將從未指定爲UTC的那種,不要忘記的SpecifyKind的返回值分配回你的對象像我有

+0

我datetime被序列化爲1303500600000 + 0000 – krisdyson 2011-04-19 13:35:36

+0

您的示例序列化爲「\/Date(1303220156217)\ /」,而我的序列化爲「\/Date(1303500600000 + 0000)\ /」。我不知道爲什麼它包括+0000 – krisdyson 2011-04-19 13:36:56

+1

你確定DateTimeKind = UTC?我只是在我的機器上再次嘗試它,當DateTimeKind不等於UTC(本地或未指定)時,輸出時區。我剛剛查看了源代碼,並且如果DateTimeKind == UTC – wal 2011-04-19 13:56:26