¿Cómo puedo formatear DateTime al formato web UTC?

89

Tengo una fecha y hora que quiero formatear a " 2009-09-01T00:00:00.000Z", pero el siguiente código me da " 2009-09-01T00:00:00.000+01:00" (ambas líneas):

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")

¿Alguna idea de cómo hacer que funcione?

Grzenio
fuente

Respuestas:

160
string foo = yourDateTime.ToUniversalTime()
                         .ToString("yyyy'-'MM'-'dd'T'HH':'mm':'ss'.'fff'Z'");
LukeH
fuente
1
@Downvoter: ¿Le gustaría decirnos qué cree que está mal con esta respuesta?
LukeH
12
Esto funcionó, pero .ToUniversalTime () estropeará su fecha existente si ya está en UTC pero la variable yourDateTime no lo especifica. Terminé eliminando .ToUniversalTime () y las fechas se alinearon con lo que se esperaba en ambos extremos (base de datos y cliente web).
Robin Vessey
10
Si la hora de su fecha ya es hora universal, puede llamar .ToUniversalTime()todo lo que quiera, no la cambiará. - Sin embargo, si tiene un valor de tiempo universal almacenado como hora local, entonces, por supuesto, lo cambiará (pero en ese caso, ¡tendrá problemas mayores con los que lidiar!) - De todos modos, esta respuesta es terrible. En su lugar, debe usar la "O"cadena de formato como se especifica en la respuesta a continuación.
BrainSlugs83
1
@ BrainSlugs83: Esta respuesta "terrible" en realidad le da el PO lo que pedían: 2009-09-01T00:00:00.000Z. El uso de la "O" especificador les daría algo diferente: 2009-09-01T00:00:00.0000000Z.
LukeH
Documentación para el formato de cadena personalizado para DateTime docs.microsoft.com/en-us/dotnet/standard/base-types/…
Mark Hebert
75

¿Por qué no utilizar el Especificador de formato de ida y vuelta ("O", "o") ?

El especificador de formato estándar "O" u "o" representa una cadena de formato de fecha y hora personalizada que utiliza un patrón que conserva la información de la zona horaria y emite una cadena de resultado que cumple con ISO 8601. Para los valores de fecha y hora, este especificador de formato está diseñado para conservar la fecha y valores de hora junto con la propiedad DateTime.Kind en el texto. La cadena formateada se puede volver a analizar mediante el método DateTime.Parse (String, IFormatProvider, DateTimeStyles) o DateTime.ParseExact si el parámetro de estilos se establece en DateTimeStyles.RoundtripKind.

El especificador de formato estándar "O" u "o" corresponde a la cadena de formato personalizado "aaaa '-' MM '-' dd'T'HH ':' mm ':' ss '.' FffffffK" para los valores de fecha y hora y al "aaaa '-' MM '-' dd'T'HH ':' mm ':' ss '.' fffffffzzz" Cadena de formato personalizado para valores DateTimeOffset. En esta cadena, los pares de comillas simples que delimitan caracteres individuales, como los guiones, los dos puntos y la letra "T", indican que el carácter individual es un literal que no se puede cambiar. Los apóstrofos no aparecen en la cadena de salida.

El especificador de formato estándar O "u" o "(y la cadena de formato personalizado" aaaa '-' MM '-' dd'T'HH ':' mm ':' ss '.' FffffffK ") aprovecha las tres formas que ISO 8601 representa la información de la zona horaria para preservar la propiedad Kind de los 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
fuente
Debido a que no funciona según lo solicitado, lo citó después de todo, "yyyy'-'MM'-'dd'T'HH':'mm':'ss'.'fffffffzzz" no es el formato Zulu.
astrowalker
@astrowalker Debería funcionar. Te dio múltiples opciones en su respuesta. Solo necesitas elegir uno. En su caso (y en los OP), usaría DateTimeKind.Utc para producir cadenas con "z" al final (también conocido como "Formato Zulu" o "Hora UTC"). Solo mire su salida de ejemplo para UTC. En mi caso, utilicé: dtVariable.ToUniversalTime().ToString("o")que se convertirá en "2019-05-26T19:50:34.4400000Z"o "yyyy-MM-ddTHH:mm:ss.fffffffZ". Nota: También probé esto con el new Date(dtDateString).getTime()método de Javscript y analiza correctamente la cadena de fecha producida por esto.
MikeTeeVee
@MikeTeeVee, solo estaba señalando que las soluciones proporcionadas no funcionarán (para DTO). La forma apropiada es dto.ToUniversalTime().ToString("yyyy'-'MM'-'dd'T'HH':'mm':'ss'.'FFFFFFF'Z'"). Para el registro, solo "o"agrega desplazamiento, no es formato Zulu.
astrowalker
1
Para aquellos que intentan hacer una transformación de cuerdas:$"{DateTime.UtcNow:O}"
Tiago César Oliveira
18
string.Format("{0:yyyy-MM-ddTHH:mm:ss.FFFZ}", DateTime.UtcNow)

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

arviman
fuente
6

El mejor formato para usar es "aaaa '-' MM '-' dd'T'HH ':' mm ':' ss '.' FffK".

La última K en la cadena se cambiará a 'Z' si la fecha es UTC o con la zona horaria (+ -hh: mm) si es local. ( http://msdn.microsoft.com/en-us/library/8kb3ddd4.aspx )

Como dijo LukeH, es bueno usar ToUniversalTime si desea que todas las fechas sean UTC.

El código final es:

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

Algunas personas han señalado que 'ToUniversalTime' es algo inseguro ya que puede causar disparos de tiempo incorrectos no deseados. Ampliando eso, estoy proporcionando un ejemplo más detallado de una solución. El ejemplo aquí crea una extensión para el objeto DateTime que devuelve de forma segura un DateTime UTC donde puede usar ToString como desee….

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
fuente
5

Quieres usar la clase DateTimeOffset .

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

lo siento, me perdí su formato original con milisegundos

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

Este código me funciona:

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
fuente
-3

Prueba esto:

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

Pregunta hecha anteriormente

Ian P
fuente
3
No estoy tratando de analizarlo (todavía), estoy tratando de imprimirlo.
Grzenio