Como posso formatar DateTime para o formato UTC da web?

90

Eu tenho um DateTime que desejo formatar para " 2009-09-01T00:00:00.000Z", mas o código a seguir me dá " 2009-09-01T00:00:00.000+01:00" (ambas as linhas):

new DateTime(2009, 9, 1, 0, 0, 0, 0, DateTimeKind.Utc).ToString("yyyy'-'MM'-'dd'T'HH':'mm':'ss'.'fffzzz")
new DateTime(2009, 9, 1, 0, 0, 0, 0, DateTimeKind.Utc).ToUniversalTime().ToString("yyyy'-'MM'-'dd'T'HH':'mm':'ss'.'fffzzz")

Alguma ideia de como fazer funcionar?

Grzenio
fonte

Respostas:

165
string foo = yourDateTime.ToUniversalTime()
                         .ToString("yyyy'-'MM'-'dd'T'HH':'mm':'ss'.'fff'Z'");
LukeH
fonte
1
@Downvoter: Você gostaria de nos dizer o que você acha que está errado com esta resposta?
LukeH
12
Isso funcionou, mas o .ToUniversalTime () bagunçará sua data existente se já estiver em UTC, mas a variável yourDateTime não a especifica. Acabei removendo o .ToUniversalTime () e as datas então alinhadas com o que era esperado nas duas pontas (banco de dados e cliente web).
Robin Vessey
10
Se a sua data e hora já for a hora universal, você pode ligar .ToUniversalTime()quanto quiser, isso não vai mudar. - No entanto, se você tem um valor de hora universal armazenado como hora local, então é claro que ele irá alterá-lo (mas, nesse caso, você terá problemas maiores para lidar!) - De qualquer forma, esta resposta é Terrível. Você deve usar a "O"string de formato conforme especificado pela resposta abaixo.
BrainSlugs83
1
@ BrainSlugs83: Essa resposta "terrível" realmente dá ao OP o que pediram: 2009-09-01T00:00:00.000Z. Usando o especificador "O" lhes daria algo diferente: 2009-09-01T00:00:00.0000000Z.
LukeH
Documentação para formatação de string personalizada para DateTime docs.microsoft.com/en-us/dotnet/standard/base-types/…
Mark Hebert
75

Por que não usar apenas o especificador de formato Round-trip ("O", "o") ?

O especificador de formato padrão "O" ou "o" representa uma string de formato de data e hora personalizada usando um padrão que preserva as informações de fuso horário e emite uma string de resultado que está em conformidade com ISO 8601. Para valores DateTime, este especificador de formato é projetado para preservar a data e valores de tempo junto com a propriedade DateTime.Kind no texto. A string formatada pode ser analisada de volta usando o método DateTime.Parse (String, IFormatProvider, DateTimeStyles) ou DateTime.ParseExact se o parâmetro styles estiver definido como DateTimeStyles.RoundtripKind.

O especificador de formato padrão "O" ou "o" corresponde à string de formato personalizado "aaaa '-' MM '-' dd'T'HH ':' mm ':' ss '.' FffffffK" para valores DateTime e "aaaa '-' MM '-' dd'T'HH ':' mm ':' ss '.' fffffffzzz" string de formato personalizado para valores DateTimeOffset. Nessa string, os pares de aspas simples que delimitam caracteres individuais, como os hifens, os dois pontos e a letra "T", indicam que o caractere individual é um literal que não pode ser alterado. Os apóstrofos não aparecem na string de saída.

O especificador de formato padrão O "ou" o "(e a string de formato personalizado" aaaa '-' MM '-' dd'T'HH ':' mm ':' ss '.' FffffffK ") tira proveito das três maneiras que ISO 8601 representa informações de fuso horário para preservar a propriedade Kind dos valores DateTime:

public class Example
{
   public static void Main()
   {
       DateTime dat = new DateTime(2009, 6, 15, 13, 45, 30, 
                                   DateTimeKind.Unspecified);
       Console.WriteLine("{0} ({1}) --> {0:O}", dat, dat.Kind); 

       DateTime uDat = new DateTime(2009, 6, 15, 13, 45, 30, 
                                    DateTimeKind.Utc);
       Console.WriteLine("{0} ({1}) --> {0:O}", uDat, uDat.Kind);

       DateTime lDat = new DateTime(2009, 6, 15, 13, 45, 30, 
                                    DateTimeKind.Local);
       Console.WriteLine("{0} ({1}) --> {0:O}\n", lDat, lDat.Kind);

       DateTimeOffset dto = new DateTimeOffset(lDat);
       Console.WriteLine("{0} --> {0:O}", dto);
   }
}
// The example displays the following output: 
//    6/15/2009 1:45:30 PM (Unspecified) --> 2009-06-15T13:45:30.0000000 
//    6/15/2009 1:45:30 PM (Utc) --> 2009-06-15T13:45:30.0000000Z 
//    6/15/2009 1:45:30 PM (Local) --> 2009-06-15T13:45:30.0000000-07:00 
//     
//    6/15/2009 1:45:30 PM -07:00 --> 2009-06-15T13:45:30.0000000-07:00
Dmitry Pavlov
fonte
Porque não funciona conforme solicitado, você o citou afinal - "yyyy'-'MM'-'dd'T'HH':'mm':'ss'.'fffffffzzz" não é o formato Zulu.
astrowalker de
@astrowalker Deve funcionar. Ele deu a você várias opções em sua resposta. Você só precisa escolher um. No seu caso (e nos OPs), você usaria DateTimeKind.Utc para produzir strings com "z" no final (também conhecido como "Formato Zulu" ou "Hora UTC"). Basta olhar para sua saída de exemplo para UTC. No meu caso, usei: dtVariable.ToUniversalTime().ToString("o")que irá converter para "2019-05-26T19:50:34.4400000Z"ou "yyyy-MM-ddTHH:mm:ss.fffffffZ". Nota: Eu também testei isso com o new Date(dtDateString).getTime()método Javscript e ele analisa corretamente a string de data produzida por isso.
MikeTeeVee
@MikeTeeVee, eu estava apenas apontando que as soluções fornecidas não funcionam (para DTO). A maneira apropriada é dto.ToUniversalTime().ToString("yyyy'-'MM'-'dd'T'HH':'mm':'ss'.'FFFFFFF'Z'"). Para o registro, apenas "o"adiciona deslocamento, não é o formato Zulu.
astrowalker
1
Para quem está tentando fazer uma transformação de string:$"{DateTime.UtcNow:O}"
Tiago César Oliveira
19
string.Format("{0:yyyy-MM-ddTHH:mm:ss.FFFZ}", DateTime.UtcNow)

retorna 2017-02-10T08: 12: 39.483Z

arviman
fonte
Você precisa usar em fffvez de FFFou 000 não será exibido por um segundo exatamente na marca.
Ryan Lundy
6

O melhor formato a ser usado é "aaaa '-' MM '-' dd'T'HH ':' mm ':' ss '.' FffK".

O último K na string será alterado para 'Z' se a data for UTC ou com fuso horário (+ -hh: mm) se for local. ( http://msdn.microsoft.com/en-us/library/8kb3ddd4.aspx )

Como disse o LukeH, é bom usar o ToUniversalTime se quiser que todas as datas sejam UTC.

O código final é:

string foo = yourDateTime.ToUniversalTime()
                         .ToString("yyyy'-'MM'-'dd'T'HH':'mm':'ss'.'fffK");
Carlos Beppler
fonte
6

Algumas pessoas apontaram que 'ToUniversalTime' é um tanto inseguro, pois pode causar exibições incorretas de hora não intencionais. Expandindo isso, estou fornecendo um exemplo mais detalhado de uma solução. O exemplo aqui cria uma extensão para o objeto DateTime que retorna com segurança um DateTime UTC onde você pode usar ToString conforme desejado….

class Program
{
    static void Main(string[] args)
    {
        DateTime dUtc = new DateTime(2016, 6, 1, 3, 17, 0, 0, DateTimeKind.Utc);
        DateTime dUnspecified = new DateTime(2016, 6, 1, 3, 17, 0, 0, DateTimeKind.Unspecified);

        //Sample of an unintended mangle:
        //Prints "2016-06-01 10:17:00Z"
        Console.WriteLine(dUnspecified.ToUniversalTime().ToString("u"));

        //Prints "2016 - 06 - 01 03:17:00Z"
        Console.WriteLine(dUtc.SafeUniversal().ToString("u"));

        //Prints "2016 - 06 - 01 03:17:00Z"
        Console.WriteLine(dUnspecified.SafeUniversal().ToString("u"));
    }
}

public static class ConvertExtensions
{
    public static DateTime SafeUniversal(this DateTime inTime)
    {
        return (DateTimeKind.Unspecified == inTime.Kind)
            ? new DateTime(inTime.Ticks, DateTimeKind.Utc)
            : inTime.ToUniversalTime();
    }
}
user3228938
fonte
5

Você deseja usar a classe DateTimeOffset .

var date = new DateTimeOffset(2009, 9, 1, 0, 0, 0, 0, new TimeSpan(0L));
var stringDate = date.ToString("u");

desculpe, eu perdi sua formatação original com os milissegundos

var stringDate = date.ToString("yyyy'-'MM'-'dd'T'HH':'mm':'ss'.'fff'Z'");
Nick Berardi
fonte
5

Este código está funcionando para mim:

var datetime = new DateTime(2017, 10, 27, 14, 45, 53, 175, DateTimeKind.Local);
var text = datetime.ToString("o");
Console.WriteLine(text);
--  2017-10-27T14:45:53.1750000+03:00

// datetime from string
var newDate = DateTime.ParseExact(text, "o", null);
Ergin Çelik
fonte
-3

Experimente isto:

DateTime date = DateTime.ParseExact(
    "Tue, 1 Jan 2008 00:00:00 UTC", 
    "ddd, d MMM yyyy HH:mm:ss UTC", 
    CultureInfo.InvariantCulture);

Pergunta anterior

Ian P
fonte
3
Não estou tentando analisar (ainda), estou tentando imprimi-lo.
Grzenio