c# - horaria - DateTime.Parse("2012-09-30T23: 00: 00.0000000Z") siempre se convierte en DateTimeKind.Local
get datetime timezone c# (5)
Como de costumbre, la respuesta de Jon es muy completa. Dicho esto, nadie ha mencionado aún DateTimeStyles.RoundtripKind
. Si desea convertir un DateTime en una cadena y volver al mismo DateTime (incluida la preservación de la configuración DateTime.Kind
), utilice el indicador DateTimeStyles.RoundtripKind
.
Como dijo Jon, lo correcto es usar el formateador "O" al convertir un objeto DateTime en una cadena. Esto preserva la información de precisión y la zona horaria. De nuevo, como dijo Jon, use DateTime.ParseExact
cuando DateTime.ParseExact
conversión de nuevo. Pero si usa DateTimeStyles.RoundtripKind, siempre recupera lo que ingresó:
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 exactamente el mismo momento que now
, incluido el hecho de que es UTC. Si ejecuta el mismo código, excepto sustituir DateTime.Now
para DateTime.UtcNow
, obtendrá una copia exacta de now
como newNow
, pero esta vez como hora local.
Para mis propósitos, esto fue lo correcto, ya que quería asegurarme de que todo lo que pasaba y se convertía se convierte de nuevo exactamente en lo mismo.
Quiero analizar una cadena que represente un DateTime en formato UTC.
Mi representación de cadena incluye la especificación de tiempo Zulu, que debería indicar que la cadena representa una hora UTC.
var myDate = DateTime.Parse("2012-09-30T23:00:00.0000000Z");
De lo anterior, esperaría que myDate.Kind fuera DateTimeKind.Utc, en cambio es DatetimeKind.Local.
¿Qué estoy haciendo mal y cómo analizar una cadena que representa una hora UTC?
¡Muchas gracias!
Puede usar el siguiente formato para el método de analizador: yyyy-MM-ddTHH:mm:ss.ffffffK
Esto procesará adecuadamente la información de zona horaria al final (a partir de .NET 2.0 ).
RE: ISO 8601
Se topó con un problema similar antes y durante varias horas (y arrancó pelos) que luego terminó usando DateTime.SpecifyKind :
DateTime.SpecifyKind(inputDate, DateTimeKind.Utc);
Creo que alguien también eludió esto en un comentario anterior también.
Use la clase TimeZoneInfo
usando lo siguiente:
var myDate = TimeZoneInfo.ConvertTimeToUtc(DateTime.Parse("2012-09-30T23:00:00.0000000Z"));
Utilizaría mi proyecto Noda Time personalmente. (Es cierto que soy parcial como el autor, pero sería más limpio ...) Pero si no puedes hacer eso ...
Utilice DateTime.ParseExact
especificando el formato exacto que espera e incluya DateTimeStyles.AssumeUniversal
y DateTimeStyles.AdjustToUniversal
en el código de análisis:
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);
}
}
(Por qué se ajustaría a local de forma predeterminada sin AdjustToUniversal
está más allá de mí, pero no importa ...)
EDITAR: solo para ampliar mis objeciones a la sugerencia de mattytommo, pretendí demostrar que perdería información. Hasta ahora he fallado, pero de una manera muy peculiar. Eche un vistazo a esto: se ejecuta en la zona horaria Europa / Londres, donde los relojes se remontan el 28 de octubre de 2012, a las 2 a.m. hora local (1 a. M. 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 una bandera "con o sin horario de verano" almacenada en algún lugar , pero me volarán si puedo averiguar dónde. Los documentos para el estado TimeZoneInfo.ConvertTimeToUtc
Si dateTime corresponde a un tiempo ambiguo, este método supone que es la hora estándar de la zona horaria de origen.
Ese no parece ser el caso aquí al convertir local2
...
EDITAR: Bien, se vuelve aún más extraño, depende de la versión del marco que estés usando. Considera 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);
}
}
Por lo tanto, esto toma dos valores UTC diferentes , los analiza con DateTime.Parse
y luego los convierte de nuevo a UTC de dos maneras diferentes.
Resultados en .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 en .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