Pregunta

[ Actualización : Los especificadores de formato no son lo mismo que las cadenas de formato; un especificador de formato es una pieza de una cadena de formato personalizada, donde una cadena de formato es 'stock' y no proporciona personalización. Mi problema es con los especificadores, no con los formatos ]

He estado intentando realizar conversiones de fecha y hora de ida y vuelta con una cadena de formato que utiliza el especificador de formato 'zzz', que sé que está vinculado a la hora local. Entonces, si intento hacer un viaje de ida y vuelta con una fecha UTC, arroja una excepción DateTimeInvalidLocalFormat, que debería, con este texto:

Un UTC DateTime se está convirtiendo a texto en un formato que solo es correcto para las horas locales. Esto puede suceder al llamar a DateTime.ToString utilizando el especificador de formato 'z', que incluirá un desplazamiento de zona horaria local en la salida. En ese caso, use el especificador de formato 'Z', que designa una hora UTC , o use la cadena de formato 'o', que es la forma recomendada de conservar una fecha y hora en el texto. Esto también puede ocurrir al pasar un DateTime para ser serializado por XmlConvert o DataSet. Si usa XmlConvert.ToString, pase XmlDateTimeSerializationMode.RoundtripKind para serializar correctamente. Si usa DataSet, establezca DateTimeMode en el objeto DataColumn en DataSetDateTime.Utc.

Basado en esta sugerencia, todo lo que necesito hacer para que mi código funcione es reemplazar 'zzz' con 'ZZZ' para poder estar en un formato UTC. El problema es que 'Z' no se encuentra en ninguna parte de la documentación y cualquier combinación de formato 'Z' que intento, es decir, 'Z', 'ZZ', 'ZZZ', siempre convierte la instancia de DateTime con esos Z tratados como literales .

¿Alguien se olvidó de implementar 'Z' sin decirle al autor del mensaje de excepción, o me estoy perdiendo cómo cambiar un desplazamiento de hora local válido con '' + 0000 ''? sin hackear?

Ejemplo de código:

// This is the format with 'zzzzz' representing local time offset
const string format = "ddd MMM dd HH:mm:ss zzzzz yyyy";

// create a UTC time
const string expected = "Fri Dec 19 17:24:18 +0000 2008";
var time = new DateTime(2008, 12, 19, 17, 24, 18, 0, DateTimeKind.Utc);

// If you're using a debugger this will rightfully throw an exception
// with .NET 3.5 SP1 because 'z' is for local time only; however, the exception
// asks me to use the 'Z' specifier for UTC times, but it doesn't exist, so it
// just spits out 'Z' as a literal.
var actual = time.ToString(format, CultureInfo.InvariantCulture);

Assert.AreEqual(expected, actual);
¿Fue útil?

Solución

Tal vez la " K " el especificador de formato sería de alguna utilidad. Este es el único que parece mencionar el uso de mayúscula "Z".

" Z " es una especie de caso único para DateTimes. El literal " Z " en realidad es parte del estándar de fecha y hora ISO 8601 para horarios UTC. Cuando " Z " (Zulu) se agrega al final de un tiempo, indica que ese tiempo es UTC, por lo que realmente el Z literal es parte del tiempo. Esto probablemente crea algunos problemas para la biblioteca de formato de fecha en .NET, ya que en realidad es un literal, en lugar de un especificador de formato.

Otros consejos

Cuando usa DateTime puede almacenar una fecha y una hora dentro de una variable.

La fecha puede ser una hora local o una hora UTC, depende de usted.

Por ejemplo, estoy en Italia (+2 UTC)

var dt1 = new DateTime(2011, 6, 27, 12, 0, 0); // store 2011-06-27 12:00:00
var dt2 = dt1.ToUniversalTime()  // store 2011-06-27 10:00:00

Entonces, ¿qué sucede cuando imprimo dt1 y dt2, incluida la zona horaria?

dt1.ToString("MM/dd/yyyy hh:mm:ss z") 
// Compiler alert...
// Output: 06/27/2011 12:00:00 +2

dt2.ToString("MM/dd/yyyy hh:mm:ss z") 
// Compiler alert...
// Output: 06/27/2011 10:00:00 +2

dt1 y dt2 contienen solo una información de fecha y hora. dt1 y dt2 no contienen el desplazamiento de la zona horaria.

Entonces, donde el " + 2 " provienen si no está contenido en la variable dt1 y dt2?

Viene de la configuración del reloj de su máquina.

El compilador le dice que cuando usa el formato 'zzz' está escribiendo una cadena que combina " FECHA + HORA " (que se almacenan en dt1 y dt2) + " TIMEZONE OFFSET " (eso no está contenido en dt1 y dt2 porque son del tipo DateTyme) y utilizará el desplazamiento de la máquina del servidor que está ejecutando el código.

El compilador le dice '' Advertencia: la salida de su código depende del desplazamiento del reloj de la máquina ''

Si ejecuto este código en un servidor ubicado en Londres (+1 UTC), el resultado será completamente diferente: en lugar de " +2 " escribirá " +1 "

...
dt1.ToString("MM/dd/yyyy hh:mm:ss z") 
// Output: 06/27/2011 12:00:00 +1

dt2.ToString("MM/dd/yyyy hh:mm:ss z") 
// Output: 06/27/2011 10:00:00 +1

La solución correcta es usar el tipo de datos DateTimeOffset en lugar de DateTime. Está disponible en SQL Server a partir de la versión 2008 y en .Net Framework a partir de la versión 3.5

Las fechas de disparo redondo a través de cadenas siempre han sido una molestia ... pero los documentos para indicar que el especificador 'o' es el que se usa para el disparo redondo que captura el estado UTC. Cuando se analiza, el resultado generalmente tendrá Kind == Utc si el original era UTC. Descubrí que lo mejor es siempre normalizar las fechas a UTC o local antes de la serialización y luego instruir al analizador sobre la normalización que ha elegido.

DateTime now = DateTime.Now;
DateTime utcNow = now.ToUniversalTime();

string nowStr = now.ToString( "o" );
string utcNowStr = utcNow.ToString( "o" );

now = DateTime.Parse( nowStr );
utcNow = DateTime.Parse( nowStr, null, DateTimeStyles.AdjustToUniversal );

Debug.Assert( now == utcNow );

Esta página en MSDN enumera cadenas de formato estándar de fecha y hora, sin incluir cadenas usando la 'Z'.

Actualización: deberá asegurarse de que el resto de la cadena de fecha también siga el patrón correcto (no ha proporcionado un ejemplo de lo que envía, por lo que es difícil decir si lo hizo o no). Para que el formato UTC funcione, debería verse así:

// yyyy'-'MM'-'dd HH':'mm':'ss'Z'
DateTime utcTime = DateTime.Parse("2009-05-07 08:17:25Z");
Label1.Text = dt.ToString("dd MMM yyyy | hh:mm | ff | zzz | zz | z");

generará:

07 Mai 2009 | 08:16 | 13 | +02:00 | +02 | +2

Estoy en Dinamarca, mi compensación de GMT es de +2 horas, la bruja es correcta.

si necesita obtener el Desplazamiento del CLIENTE , le recomiendo que compruebe un pequeño truco que hice. La página está en un servidor en el Reino Unido donde GMT es +00: 00 y, como puede ver, obtendrá su compensación GMT local.


Con respecto a tu comentario, hice:

DateTime dt1 = DateTime.Now;
DateTime dt2 = dt1.ToUniversalTime();

Label1.Text = dt1.ToString("dd MMM yyyy | hh:mm | ff | zzz | zz | z");
Label2.Text = dt2.ToString("dd MMM yyyy | hh:mm | FF | ZZZ | ZZ | Z");

y obtengo esto:

07 Mai 2009 | 08:24 | 14 | +02:00 | +02 | +2
07 Mai 2009 | 06:24 | 14 | ZZZ | ZZ | Z 

No obtengo Excepción, solo que ... no hace nada con Z mayúscula :(

Lo siento, pero ¿me estoy perdiendo algo?


Leer atentamente el MSDN en Cadenas de formato de fecha y hora personalizadas

no hay soporte para mayúsculas 'Z'.

Estaba tratando con DateTimeOffset y desafortunadamente el " o " imprime " + 0000 " no " Z " ;.

Así que terminé con:

dateTimeOffset.UtcDateTime.ToString("o")
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top