2010-08-24 23 views
80

He encontrado cómo convertir un DateTime en un formato ISO 8601, pero nada sobre cómo hacer lo contrario en C#.Cómo crear un .NET DateTime desde el formato ISO 8601

Tengo 2010-08-20T15:00:00Z, y quiero convertirlo en un objeto DateTime.

Podría separar las partes de la cadena, pero parece mucho trabajo para algo que ya es un estándar internacional.

+1

posible duplicado de [Convertir cadena a fecha en .NET] (http://stackoverflow.com/questions/2188585/convert-string-to-date-in-net) – abatishchev

+2

Buscar primero por favor. Esta es una pregunta número 100 sobre este tema en este mes – abatishchev

+8

@abatishchev no, esto no es un duplicado de esa pregunta. Tal vez deberías leer la pregunta primero antes de responder. – Aidin

Respuesta

87

Esta solución hace uso de la DateTimeStyles enumeración, y también trabaja con Z.

DateTime d2 = DateTime.Parse("2010-08-20T15:00:00Z", null, System.Globalization.DateTimeStyles.RoundtripKind); 

Esto imprime la solución perfecta.

+0

@Mamta Dalal: prueba 'DateTime.ParseExact (" 2010-08-20T15: 00: 00Z "," s ", CultureInfo.InvariantCulture);' No funciona. –

+3

La solución editada de 'DateTime d2 = DateTime.Parse (" 2010-08-20T15: 00: 00Z ", null, DateTimeStyles.RoundtripKind);' parece funcionar bien. – j3ko

+0

@ j3ko gracias –

0

DateTime.ParseExact(...) le permite decirle al analizador qué representa cada personaje.

21
using System.Globalization; 

DateTime d; 
DateTime.TryParseExact(
    "2010-08-20T15:00:00", 
    "s", 
    CultureInfo.InvariantCulture, 
    DateTimeStyles.AssumeUniversal, out d); 
+1

produce False y d ~~> "1/1/0001 12:00:00 AM" en LinqPad :( –

+0

@Reb: "2010-08-20T15: 00: 00" y "s", si no es "Z" en el extremo – abatishchev

+0

corregido :) la Z aparece en todas mis muestras (que provienen de varias unidades de GPS y archivos GPX) –

12

Esta es la que funciona mejor para mí (LINQPad versión):

DateTime d; 
DateTime.TryParseExact(
    "2010-08-20T15:00:00Z", 
    @"yyyy-MM-dd\THH:mm:ss\Z", 
    CultureInfo.InvariantCulture, 
    DateTimeStyles.AssumeUniversal, 
    out d); 
d.ToString() 

produce

true 
8/20/2010 8:00:00 AM 
+0

Excelente solución, gracias. – kamui

+0

Actualmente estoy usando esto para verificar en mi unidad que todas las cadenas que espero sean fechas son de formato Iso8601. ¡Gracias! – anthv123

3

Parece importante para que coincida exactamente el formato de la cadena de la ISO para TryParseExact a trabajo. Supongo que Exact is Exact y esta respuesta es obvia para la mayoría, pero de todos modos ...

En mi caso, la respuesta de Reb.Cabin no funciona ya que tengo una entrada ligeramente diferente según mi "valor" a continuación.

Valor: 2012-08-10T14:00:00.000Z

Hay algunos de 000 extras en allí para milisegundos y puede haber más.

Sin embargo, si agrego algunos .fff al formato que se muestra a continuación, todo está bien.

Cadena de formato: @"yyyy-MM-dd\THH:mm:ss.fff\Z"

En VS2010 ventana Inmediato:

DateTime.TryParseExact(value,@"yyyy-MM-dd\THH:mm:ss.fff\Z", CultureInfo.InvariantCulture,DateTimeStyles.AssumeUniversal, out d); 

cierto

Puede que tenga que utilizar DateTimeStyles.AssumeLocal y dependiendo de qué zona de su tiempo es para ...

2

Esto funciona bien en LINQPad4:

Console.WriteLine(DateTime.Parse("2010-08-20T15:00:00Z")); 
Console.WriteLine(DateTime.Parse("2010-08-20T15:00:00")); 
Console.WriteLine(DateTime.Parse("2010-08-20 15:00:00")); 
17

Aunque MSDN dice que los formatos "s" y "o" reflejan el estándar, parecen ser capaces de analizar solo un subconjunto limitado de él. Especialmente es un problema si la cadena contiene la especificación de zona horaria. (Ni tampoco para formatos básicos ISO8601, o formatos de precisión reducidos, sin embargo, este no es exactamente su caso). Es por eso que uso cadenas de formato personalizadas cuando se trata de analizar ISO8601.Actualmente mi fragmento preferido es:

static readonly string[] formats = { 
    // Basic formats 
    "yyyyMMddTHHmmsszzz", 
    "yyyyMMddTHHmmsszz", 
    "yyyyMMddTHHmmssZ", 
    // Extended formats 
    "yyyy-MM-ddTHH:mm:sszzz", 
    "yyyy-MM-ddTHH:mm:sszz", 
    "yyyy-MM-ddTHH:mm:ssZ", 
    // All of the above with reduced accuracy 
    "yyyyMMddTHHmmzzz", 
    "yyyyMMddTHHmmzz", 
    "yyyyMMddTHHmmZ", 
    "yyyy-MM-ddTHH:mmzzz", 
    "yyyy-MM-ddTHH:mmzz", 
    "yyyy-MM-ddTHH:mmZ", 
    // Accuracy reduced to hours 
    "yyyyMMddTHHzzz", 
    "yyyyMMddTHHzz", 
    "yyyyMMddTHHZ", 
    "yyyy-MM-ddTHHzzz", 
    "yyyy-MM-ddTHHzz", 
    "yyyy-MM-ddTHHZ" 
    }; 

public static DateTime ParseISO8601String (string str) 
{ 
    return DateTime.ParseExact (str, formats, 
     CultureInfo.InvariantCulture, DateTimeStyles.None); 
} 

Si no le importa analizar cadenas TZ-menos (yo), se puede añadir una línea de "s" para ampliar en gran medida el número de alteraciones de formato cubiertos.

+2

Agregaría '" aaaamMMdd "' en la matriz de "formatos" para una precisión reducida a días, ya que este es el caso cuando una RFC 5545 RRULE dependerá de una DTSTART para proporcionar la hora. –

+0

Usar 'K' le permite rodar sus diferentes manejos de zona horaria juntos. Tengo una variante más extensa en http://stackoverflow.com/a/31246449/400547 pero es algo demasiado extenso (acepta cosas que son válidas ISO 8601 pero no se usan en los perfiles más comunes) pero muestra cómo 'K 'puede reducir el tamaño en un tercio. –

Cuestiones relacionadas