Como criar um .NET DateTime a partir do formato ISO 8601


130

Eu descobri como transformar um DateTime em um ISO 8601 formato , mas nada sobre como fazer o inverso em c #.

Eu tenho 2010-08-20T15:00:00Z, e quero transformá-lo em um DateTimeobjeto.

Eu mesmo poderia separar as partes da corda, mas isso parece muito trabalho para algo que já é um padrão internacional.


1
possível duplicado de Convert String to Date no .NET
abatishchev

1
@Aidin: 24 '10 agosto às 12:02
abatishchev

@Aidin: e sim, esta é uma duplicata. A única diferença de formato. O resto é o mesmo.
abatishchev

6
@abatishchev, e é por isso que não é uma duplicata. A resposta na "duplicado" não manipula 8601.
Spiralis

3
Sim, isso não é uma duplicata. Esta pergunta é específica para analisar o formato ISO 8601.
Jose

Respostas:


142

Esta solução utiliza a enumeração DateTimeStyles e também funciona com Z.

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

Isso imprime a solução perfeitamente.


3
A solução editada de DateTime d2= DateTime.Parse("2010-08-20T15:00:00Z", null, DateTimeStyles.RoundtripKind);parece funcionar bem.
J3ko

4
Qualquer pessoa que deseje elaborar essa DateTimeStyles.RoundtripKind? descrição do MSDN está em branco.
21415 Steve Parish

8
parece que esta pergunta foi editada para refletir uma resposta melhor, mas como @MamtaD substituiu a resposta original, os comentários se tornam muito enganosos. No começo eu não tinha certeza de que a resposta é correta devido aos comentários no topo, mas então eu percebi que resposta incorreta foi posteriormente substituída por uma correta
Aidin

5
Não funciona para mim com dígitos fracionários. 2018-06-19T14:56:14.123Zé analisado como hora local, não como UTC. Eu uso em CultureInfo.InvariantCulturevez de nulo.
Erik Hart

1
Para mais informações sobre DateTimeStyles.RoundTripKind, consulte stackoverflow.com/q/39572395/2014893
Robert K. Sino

33

Embora o MSDN diga que os formatos "s" e "o" refletem o padrão, eles parecem capazes de analisar apenas um subconjunto limitado dele. Especialmente, é um problema se a string contiver especificação de fuso horário. (Nem nos formatos ISO8601 básicos ou nos formatos de precisão reduzida - no entanto, esse não é exatamente o seu caso.) É por isso que uso seqüências de caracteres de formato personalizado quando se trata de analisar o ISO8601. Atualmente, meu snippet preferido é:

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 );
}

Se você não se importa de analisar cadeias sem TZ (sim), você pode adicionar uma linha "s" para aumentar bastante o número de alterações de formato cobertas.


3
Eu acrescentaria "yyyyMMdd"na formatsmatriz uma precisão reduzida a dias, pois às vezes é o caso em que uma RFC 5545 RRULE conta com um DTSTART para fornecer o tempo.
Kyle Falconer

1
O uso Kpermite rolar os diferentes tratamentos de fuso horário juntos. Eu tenho uma variante mais extensa em stackoverflow.com/a/31246449/400547, mas é muito extensa (aceita coisas que são válidas ISO 8601, mas não usadas nos perfis mais comuns), mas mostra como Kreduzir o tamanho por um terceiro.
9609 Jon Hanna

20
using System.Globalization;

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

1
produz False ed ~~> "1/1/0001 12:00:00" no LinqPad :(
Reb.Cabin

@Reb: "2010-08-20T15: 00: 00" e "s", se não houver "Z" no final
abatishchev

corrigida :) os shows Z-se em todas as minhas amostras (que acontecem vir de várias unidades de GPS e arquivos GPX)
Reb.Cabin

Descobri em outra referência ISO 8601 que o "Z" significa Zona - como no Fuso Horário.
Reb.Cabin 17/05

30
Z realmente significa hora Zulu ou UTC. pt.wikipedia.org/wiki/ISO_8601#UTC
Peter Stephens

19

Aqui está um que funciona melhor para mim ( versão LINQPad ):

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

produz

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

Atualmente, estou usando isso para verificar em meus testes de unidade que todas as strings que espero serem datas são do formato Iso8601. Obrigado!
precisa saber é

1
Por que isso retorna um carimbo de data / hora que não está no UTC ?! Uma grande violação do Princípio do Menor Espanto, uma vez que a "cultura invariável" com "AssumeUniversal" não deveria estar fazendo isso porque o horário de verão difere muito do mundo todo; portanto, o retorno no fuso horário local pode causar erros se você começar a executar o código em um servidor com configurações diferentes!
Elaskanator

7

Parece importante corresponder exatamente ao formato da string ISO para TryParseExactfuncionar. Eu acho que exato é exato e esta resposta é óbvia para a maioria, mas de qualquer maneira ...

No meu caso, a resposta do Reb.Cabin não funciona, pois tenho uma entrada ligeiramente diferente conforme meu "valor" abaixo.

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

Existem alguns milhares extras por milissegundos e pode haver mais.

No entanto, se eu adicionar alguns .fff ao formato, como mostrado abaixo, está tudo bem.

Formatar sequência: @"yyyy-MM-dd\THH:mm:ss.fff\Z"

Na janela imediata do VS2010:

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

verdade

Você pode ter que usar DateTimeStyles.AssumeLocaltambém, dependendo de qual zona é o seu tempo ...


1
Isso funcionou para mim, mas eu também tive que mudar AssumeUniversalpara AdjustToUniversal.
Augusto Barreto

4

Isso funciona bem no 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"));

-1

DateTime.ParseExact(...) permite que você diga ao analisador o que cada caractere representa.

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.