2008-10-07 38 views
244

Estamos desarrollando una aplicación C# para un cliente de servicio web. Esto se ejecutará en PC con Windows XP.Convertir hora UTC/GMT a hora local

Uno de los campos devueltos por el servicio web es un campo DateTime. El servidor devuelve un campo en formato GMT, es decir, con una "Z" al final.

Sin embargo, encontramos que .NET parece hacer algún tipo de conversión implícita y el tiempo siempre fue de 12 horas.

El siguiente ejemplo de código resuelve esto en cierta medida, ya que la diferencia de 12 horas se ha ido pero no tiene en cuenta el horario de verano de Nueva Zelanda.

CultureInfo ci = new CultureInfo("en-NZ"); 
string date = "Web service date".ToString("R", ci); 
DateTime convertedDate = DateTime.Parse(date);    

Según this date site:

UTC/GMT Offset

Hora estándar: UTC/GMT +12 horas
Horario de verano: 1 hora zona
Hora local actual : UTC/GMT +13 horas

¿Cómo nos ajustamos para la hora extra? ¿Se puede hacer esto de forma programática o se trata de algún tipo de ajuste en la PC?

+1

el 'tiempo Z' refiere a UTC, no GMT. Los dos pueden diferir en hasta 0.9 segundos. – mc0e

Respuesta

42
TimeZone.CurrentTimeZone.ToLocalTime(date); 
+8

Esto solo funciona si el sistema sabe que la fecha de conversión está en UTC. Por favor mira mi respuesta. –

+1

Pero UTC es el valor predeterminado, ¿no? Por lo tanto, funciona para "no especificado" como en la respuesta de CJ7. – NickG

2

En respuesta a la sugerencia de Dana:

El ejemplo de código ahora se ve así:

string date = "Web service date"..ToString("R", ci); 
DateTime convertedDate = DateTime.Parse(date);    
DateTime dt = TimeZone.CurrentTimeZone.ToLocalTime(convertedDate); 

La fecha original era 20/08/08; el tipo era UTC.

Ambos "convertedDate" y "DT" son los mismos:

21/08/08 10:00:26; el tipo era local

+0

Consulte mi respuesta para obtener una explicación de esto. –

1

Tuve el problema de que se trataba de un conjunto de datos que se enviaba a través del cable (servicio web al cliente) que cambiaría automáticamente porque el campo DateType de DataColumn se estableció en local. Asegúrese de verificar qué es DateType si está presionando DataSets.

Si usted no quiere que cambie, la pusieron a no especificado

13

Sólo me gustaría añadir una nota general de precaución.

Si todo lo que hace es obtener la hora actual del reloj interno de la computadora para poner una fecha/hora en la pantalla o un informe, entonces todo está bien. Pero si está guardando la información de fecha/hora para referencia posterior o si está calculando fecha/hora, ¡cuidado!

Digamos que usted determina que un crucero llegó a Honolulu el 20 de diciembre de 2007 a las 15:00 UTC. Y quieres saber qué hora local fue esa.
1. Probablemente haya al menos tres "lugareños" involucrados. Local puede significar Honolulu, o puede significar dónde se encuentra su computadora, o puede significar la ubicación donde se encuentra su cliente.
2. Si usa las funciones integradas para realizar la conversión, probablemente sea incorrecta. Esto se debe a que el horario de verano es (probablemente) actualmente en vigencia en su computadora, pero NO estuvo en vigencia en diciembre. Pero Windows no lo sabe ... todo lo que tiene es una bandera para determinar si el horario de verano está vigente. Y si está actualmente en vigencia, agregará felizmente una hora incluso a una fecha en diciembre.
3. El horario de verano se implementa de forma diferente (o no se aplica) en varias subdivisiones políticas. No piense que solo porque su país cambia en una fecha específica, también lo harán otros países.

+5

En realidad, el # 2 no es del todo correcto. De hecho, existen reglas sobre DST en cada zona horaria que su computadora sabrá si la información se ha instalado (y actualizado). Para muchas zonas, esas reglas son fijas. Otros implementan "DST dinámico". Brasil es mi favorito por esto. Sin embargo, en resumen, su cómputo puede funcionar si su hora local sería DST en diciembre, suponiendo que ningún cambio pasa a ser ley de aquí a entonces. –

+0

Incluso si no vives en Brasil, el horario de verano es "dinámico" porque los políticos pueden cambiarlo en cualquier momento (como se hizo hace unos años en los EE. UU.). Como la mayoría del software está escrito teniendo en cuenta el uso futuro, es importante darse cuenta de que NO EXISTE ninguna forma práctica, predecible o incluso teórica de saber qué reglas del horario de verano tendrán vigencia. Puede acercarse, pero ahórrese un poco de frustración renunciando a la perfección. – DaveWalley

4

no se olvide si ya tiene un objeto DateTime y no está seguro si es UTC o local, que es bastante fácil de utilizar los métodos del objeto directamente:

DateTime convertedDate = DateTime.Parse(date); 
DateTime localDate = convertedDate.ToLocalTime(); 

¿Cómo nos ajustamos por la hora extra?

A menos que se especifique .net utilizará la configuración de la PC local. Tendría una lectura de: http://msdn.microsoft.com/en-us/library/system.globalization.daylighttime.aspx

Por el aspecto del código podría ser algo como:

DaylightTime daylight = TimeZone.CurrentTimeZone.GetDaylightChanges(year); 

Y como se mencionó anteriormente vuelva a comprobar lo que el establecimiento de zona horaria de su servidor está encendido. Hay artículos en la red sobre cómo afectar de forma segura los cambios en IIS.

+0

El sistema se ocupará de esta compatibilidad para usted, siempre que le informe al sistema de qué tipo es su fecha (local/utc/no especificada). –

103

Me gustaría utilizar la clase System.TimeZoneInfo si está en .NET 3.5. Ver http://msdn.microsoft.com/en-us/library/system.timezoneinfo.aspx. Esto debería tener en cuenta los cambios de horario de verano correctamente.

// Coordinated Universal Time string from 
// DateTime.Now.ToUniversalTime().ToString("u"); 
string date = "2009-02-25 16:13:00Z"; 
// Local .NET timeZone. 
DateTime localDateTime = DateTime.Parse(date); 
DateTime utcDateTime = localDateTime.ToUniversalTime(); 

// ID from: 
// "HKEY_LOCAL_MACHINE\Software\Microsoft\Windows NT\CurrentVersion\Time Zone" 
// See http://msdn.microsoft.com/en-us/library/system.timezoneinfo.id.aspx 
string nzTimeZoneKey = "New Zealand Standard Time"; 
TimeZoneInfo nzTimeZone = TimeZoneInfo.FindSystemTimeZoneById(nzTimeZoneKey); 
DateTime nzDateTime = TimeZoneInfo.ConvertTimeFromUtc(utcDateTime, nzTimeZone); 
+0

Si está trabajando en su propia zona horaria (en-NZ en este caso), entonces no necesita lidiar con TimeZoneInfo. Es solo una complejidad innecesaria. Ver mi respuesta para más detalles. –

+32

+1 por no asumir que el servidor está en Nueva Zelanda – ajbeaven

+8

Y si alguien necesita, aquí está la lista de zonas horarias que he encontrado para TimeZoneInfo.FindSystemTimeZoneById - http://www.codeproject.com/Messages/3867850/Csharp-NET- List-of-timezones-for-TimeZoneInfo-Find.aspx – kape123

329

Para las cadenas tales como 2012-09-19 01:27:30.000, DateTime.Parse no lo sé a qué hora zona de la fecha y la hora son de.

DateTime tiene un tipo propiedad, que puede tener una de las opciones de zona tres veces:

  • no especificados
  • local
  • Utc

NOTASi está Deseando representar una fecha/hora que no sea UTC o su tim local e zone, entonces deberías usar DateTimeOffset.


Así que para el código en su pregunta:

DateTime convertedDate = DateTime.Parse(dateStr); 

var kind = convertedDate.Kind; // will equal DateTimeKind.Unspecified 

Usted dice que sabe de qué tipo es, por lo que se dice.

DateTime convertedDate = DateTime.SpecifyKind(
    DateTime.Parse(dateStr), 
    DateTimeKind.Utc); 

var kind = convertedDate.Kind; // will equal DateTimeKind.Utc 

Ahora, una vez que el sistema conoce su tiempo en UTC, sólo puede llamar a ToLocalTime:

DateTime dt = convertedDate.ToLocalTime(); 

esto le dará el resultado que necesita.

+17

simplemente otra forma de especificar el tipo: 'DateTime convertedTime = new DateTime (DateTime.Parse (dateStr) .Ticks), DateTimeKind.Utc);' – Brad

+0

¿no es ToLocalTime()? @rad: tus pares no coinciden. – TrueWill

+0

Gracias @TrueWill. Actualizado. –

1

Me encontré con esta pregunta ya que estaba teniendo un problema con las fechas UTC que recibes a través de la API de Twitter (created_at campo en un estado); Necesito convertirlos a DateTime. Ninguna de las respuestas/muestras de código en las respuestas en esta página fueron suficientes para evitar que recibiera un error "Cadena no reconocida como fecha y hora válida" (pero es lo más cercano que tengo para encontrar la respuesta correcta en SO)

Publicar este enlace aquí en caso de que esto ayude a alguien más - la respuesta que necesitaba era encontrar en esta entrada del blog: http://www.wduffy.co.uk/blog/parsing-dates-when-aspnets-datetimeparse-doesnt-work/ - básicamente utilizar DateTime.ParseExact con una cadena de formato en lugar de DateTime.Parse

15

sé que esto es una cuestión mayor , pero me encontré con una situación similar, y quería compartir lo que había encontrado para futuros buscadores, posiblemente incluyéndome a mí mismo :).

DateTime.Parse() puede ser complicado - ver here por ejemplo.

Si el DateTime proviene de un servicio web o alguna otra fuente con un formato conocido, es posible que desee considerar algo así como

DateTime.ParseExact(dateString, 
        "MM/dd/yyyy HH:mm:ss", 
        CultureInfo.InvariantCulture, 
        DateTimeStyles.AssumeUniversal | DateTimeStyles.AdjustToUniversal) 

o, mejor aún,

DateTime.TryParseExact(...) 

El AssumeUniversal la bandera le dice al analizador que la fecha/hora ya es UTC; la combinación de AssumeUniversal y AdjustToUniversal le dice que no convierta el resultado a la hora "local", que intentará hacer de forma predeterminada. (Personalmente trato de tratar exclusivamente con UTC en la (s) capa (s) de negocio/aplicación/servicio de todos modos. Pero omitir la conversión a la hora local también acelera las cosas: en un 50% o más en mis pruebas, ver más abajo).

Esto es lo que hacíamos antes:

DateTime.Parse(dateString, new CultureInfo("en-US")) 

habíamos perfilado de la aplicación y se encontró que el DateTime.Parse representa un porcentaje significativo del uso de la CPU. (Por cierto, el constructor fue CultureInfo no contribuye de manera significativa a uso de la CPU.)

Así que creó una aplicación de consola para analizar una cadena de fecha/hora 10000 veces en una variedad de maneras. En pocas palabras:
Parse() 10 seg
ParseExact() (conversión a local) 20-45 ms
ParseExact() (no convertir a local) 10-15 ms
... y sí, los resultados para Parse() están en segundos , mientras que los otros están en milisegundos.

+3

+1 Para crear perfiles de los métodos de análisis. ¡Bueno saber! –

15

DateTime objetos tienen el Kind de Unspecified por defecto, que para los fines de ToLocalTime se supone que es UTC.

para obtener la hora local de un objeto UnspecifiedDateTime, que, por tanto, sólo tiene que hacer esto:

convertedDate.ToLocalTime(); 

El paso de cambiar el Kind del DateTime a partir Unspecified a UTC es innecesaria.Unspecified se supone que es UTC para los fines de ToLocalTime: http://msdn.microsoft.com/en-us/library/system.datetime.tolocaltime.aspx

+1

Y viceversa: 'convertedDate.FromLocalTime();' convertirá a 'UTC'. –

1
@TimeZoneInfo.ConvertTimeFromUtc(timeUtc, TimeZoneInfo.Local) 
Cuestiones relacionadas