2011-04-15 12 views
6

Tengo una fecha y hora en la base de datos y la recupero de la base de datos usando Entity Framework, luego paso los datos a través de la API JSON a través del DataContractJsonSerializer.DataContractJsonSerializer DateTime implícita conversión de zona horaria

La hora en el campo de fecha y hora parece haberse ajustado de acuerdo con la zona horaria local del servidor mientras se está procesando en DataContractJsonSerializer. La época expresada en tiempo es 1 hora antes del tiempo esperado. DateTime Kind es UTC, pero anteriormente no estaba especificado y tuve el mismo problema.

En mi aplicación, deseo convertir entre zonas horarias explícitamente y en el lado del cliente, no el servidor, ya que esto tiene más sentido. Me sorprende esta funcionalidad implícita ya que mis valores de fecha y hora deben ser valores simples como un entero.

gracias

Respuesta

4

DataContractJsonSerializer salida será la parte de zona horaria (+ zzzz) si su DateTime.Kind es igual al local o no especificado. Este comportamiento difiere del XmlSerializer que solo genera la porción de zona horaria si Kind es igual a No especificado.

Si curiosa la salida de la fuente de JsonWriterDelegator que contiene el siguiente método:

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

Me he encontrado la siguiente prueba en mi máquina

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

     } 

que produce el resultado esperado:

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

Por lo tanto, en algún momento su fecha debe ser Unspecified o Lo California.

Después de sacarla de la base de datos convertir el tipo de especificar a UTC llamando

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

y no se olvide de asignar el valor de retorno de SpecifyKind de nuevo en su objeto como si tuviera

+0

Mi datetime se serializa al 1303500600000 + 0000 – krisdyson

+0

Su muestra se serializa a "\/Date (1303220156217) \ /" mientras que la mía se serializa a "\/Date (1303500600000 + 0000) \ /". No sé por qué está incluido el +0000 – krisdyson

+1

¿estás seguro DateTimeKind = UTC? Lo intenté de nuevo en mi máquina y cuando DateTimeKind NO es igual a UTC (Local o No especificado), se genera la zona horaria. Acabo de ver también el código fuente y no se mostrará la zona horaria si DateTimeKind == UTC – wal

Cuestiones relacionadas