32 votos

DateTime.Parse("2012-09-30T23:00:00.0000000 Z") siempre convierte a DateTimeKind.Local

Quiero analizar una cadena que representa un DateTime en formato UTC.

Mi representación de cadena incluye la hora Zulu especificación que debe indicar que la cadena de representar a una hora UTC.

var myDate = DateTime.Parse("2012-09-30T23:00:00.0000000Z");    

De lo anterior yo esperaría myDate.Tipo DateTimeKind.Utc, sino que es DatetimeKind.Local.

¿Qué estoy haciendo mal y cómo Analizar una cadena que representa una hora UTC?

Muchas gracias!

46voto

Jon Skeet Puntos 692016

Me gustaría utilizar Noda Tiempo personalmente, pero si usted no puede hacer eso...

Utilice DateTime.ParseExact especificar el formato exacto que usted espera, y se incluyen DateTimeStyles.AssumeUniversal y DateTimeStyles.AdjustToUniversal en el análisis de código:

using System;
using System.Globalization;

class Test
{
    static void Main()        
    {
        var date = DateTime.ParseExact("2012-09-30T23:00:00.0000000Z",
                                       "yyyy-MM-dd'T'HH:mm:ss.fffffff'Z'",
                                       CultureInfo.InvariantCulture,
                                       DateTimeStyles.AssumeUniversal |
                                       DateTimeStyles.AdjustToUniversal);
        Console.WriteLine(date);
        Console.WriteLine(date.Kind);
    }
}

(Muy bien por qué se ajustaría a los locales por defecto sin AdjustToUniversal está más allá de mí, pero no importa...)

EDIT: Acaba de ampliar mis objeciones a mattytommo la sugerencia, he intentado demostrar que perdería la información. He fallado hasta ahora, pero de un modo muy peculiar. Eche un vistazo a esto - que se ejecuta en la Europa/Londres de la zona de tiempo, donde los relojes volver el 28 de octubre de 2012, a las 2 de la madrugada hora local (1am UTC):

DateTime local1 = DateTime.Parse("2012-10-28T00:30:00.0000000Z");
DateTime local2 = DateTime.Parse("2012-10-28T01:30:00.0000000Z");
Console.WriteLine(local1 == local2); // True

DateTime utc1 = TimeZoneInfo.ConvertTimeToUtc(local1);
DateTime utc2 = TimeZoneInfo.ConvertTimeToUtc(local2);
Console.WriteLine(utc1 == utc2); // False. Hmm.

Parece que hay un "con o sin horario de verano" de la bandera de ser almacenados en algún lugar, pero voy a ser soplan si puedo trabajar donde. La documentación para el TimeZoneInfo.ConvertTimeToUtc estado

Si dateTime corresponde a una ambigua tiempo, este método supone que es el tiempo estándar de la fuente de la zona horaria.

Que no parecen ser el caso aquí cuando la conversión de local2...

EDIT: Vale, es aún desconocido - depende de la versión del framework que está utilizando. Considere la posibilidad de este programa:

using System;
using System.Globalization;

class Test
{
    static void Main()        
    {
        DateTime local1 = DateTime.Parse("2012-10-28T00:30:00.0000000Z");
        DateTime local2 = DateTime.Parse("2012-10-28T01:30:00.0000000Z");

        DateTime utc1 = TimeZoneInfo.ConvertTimeToUtc(local1);
        DateTime utc2 = TimeZoneInfo.ConvertTimeToUtc(local2);
        Console.WriteLine(utc1);
        Console.WriteLine(utc2);

        DateTime utc3 = local1.ToUniversalTime();
        DateTime utc4 = local2.ToUniversalTime();
        Console.WriteLine(utc3);
        Console.WriteLine(utc4);
    }
}

Así que esto se hace de dos diferentes UTC valores, analiza con DateTime.Parse, luego los convierte de nuevo a UTC en dos formas diferentes.

Resultados de la virtud .NET 3.5:

28/10/2012 01:30:00 // Look - we've lost information
28/10/2012 01:30:00
28/10/2012 00:30:00 // But ToUniversalTime() seems okay...
28/10/2012 01:30:00

Resultados de la virtud .NET 4.5 beta:

28/10/2012 00:30:00 // It's okay!
28/10/2012 01:30:00
28/10/2012 00:30:00
28/10/2012 01:30:00

13voto

iny Puntos 352

Como de costumbre, Jon respuesta es muy completo. Dicho esto, nadie ha mencionado aún DateTimeStyles.RoundtripKind. Si desea convertir un DateTime a una cadena y volver a la misma DateTime (que incluye la preservación de la DateTime.Kind de ajuste), el uso de la DateTimeStyles.RoundtripKind bandera.

Como dijo Jon, lo correcto es el uso de la "S" formateador al convertir un objeto DateTime a una cadena. Esto preserva tanto la precisión y la información de zona horaria. De nuevo, como dijo Jon, uso DateTime.ParseExact cuando la conversión de la espalda. Pero si usted utiliza DateTimeStyles.RoundtripKind, usted siempre consigue lo que usted pone en:

var now = DateTime.UtcNow;
var strNow = now.ToString("O");
var newNow = DateTime.ParseExact(strNow, "O", CultureInfo.InvariantCulture, DateTimeStyles.RoundtripKind);

En el código anterior, newNow es un exacto mismo tiempo como now, incluyendo el hecho de que es la hora UTC. Si se ejecuta el mismo código, excepto sustituto DateTime.Now para DateTime.UtcNow, obtendrá una copia exacta de now de nuevo como newNow, pero esta vez, como la hora local.

Para mis propósitos, esto era lo correcto ya que yo quería hacer, que seguro que lo que se aprobó y se convierte en se convierte de nuevo a lo mismo.

3voto

mattytommo Puntos 27587

El uso de la TimeZoneInfo clase utilizando las siguientes:

var myDate = TimeZoneInfo.ConvertTimeToUtc(DateTime.Parse("2012-09-30T23:00:00.0000000Z"));

1voto

port443 Puntos 138

Puede utilizar el siguiente formato para el analizador método: yyyy-MM-ddTHH:mm:ss.ffffffK

Este deberá procesar correctamente la información de zona horaria en la final (a partir de .NET 2.0).

RE: ISO 8601

Iteramos.com

Iteramos es una comunidad de desarrolladores que busca expandir el conocimiento de la programación mas allá del inglés.
Tenemos una gran cantidad de contenido, y también puedes hacer tus propias preguntas o resolver las de los demás.

Powered by:

X