Comment puis-je formater DateTime au format Web UTC?

89

J'ai un DateTime que je veux formater en " 2009-09-01T00:00:00.000Z", mais le code suivant me donne " 2009-09-01T00:00:00.000+01:00" (les deux lignes):

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

Des idées pour le faire fonctionner?

Grzenio
la source

Réponses:

160
string foo = yourDateTime.ToUniversalTime()
                         .ToString("yyyy'-'MM'-'dd'T'HH':'mm':'ss'.'fff'Z'");
LukeH
la source
1
@Downvoter: Voulez-vous nous dire ce qui ne va pas avec cette réponse?
LukeH
12
Cela a fonctionné mais le .ToUniversalTime () gâchera votre date existante si elle est déjà à UTC mais la variable yourDateTime ne le spécifie pas. J'ai fini par supprimer le .ToUniversalTime () et les dates s'alignaient alors avec ce qui était attendu aux deux extrémités (base de données et client Web).
Robin Vessey
10
Si votre date et heure est déjà l'heure universelle, vous pouvez appeler .ToUniversalTime()tout ce que vous voulez, cela ne la changera pas. - Cependant, si vous avez une valeur de temps universel stockée en tant qu'heure locale, alors bien sûr elle la changera (mais dans ce cas, vous avez de plus gros problèmes à résoudre!) - Quoi qu'il en soit, cette réponse est terrible. Vous devez utiliser la "O"chaîne de format comme spécifié par la réponse ci-dessous, à la place.
BrainSlugs83
1
@ BrainSlugs83: Ce « terrible » réponse donne en fait l'OP ce qu'ils demandaient: 2009-09-01T00:00:00.000Z. En utilisant le spécificateur « O » serait leur donner quelque chose de différent: 2009-09-01T00:00:00.0000000Z.
LukeH
Documentation pour le formatage de chaîne personnalisé pour DateTime docs.microsoft.com/en-us/dotnet/standard/base-types/…
Mark Hebert
75

Pourquoi ne pas simplement utiliser le spécificateur de format aller-retour ("O", "o") ?

Le spécificateur de format standard «O» ou «o» représente une chaîne de format de date et d'heure personnalisée utilisant un modèle qui préserve les informations de fuseau horaire et émet une chaîne de résultat conforme à ISO 8601. Pour les valeurs DateTime, ce spécificateur de format est conçu pour préserver la date et les valeurs d'heure avec la propriété DateTime.Kind dans le texte. La chaîne mise en forme peut être analysée à l'aide de la méthode DateTime.Parse (String, IFormatProvider, DateTimeStyles) ou DateTime.ParseExact si le paramètre styles est défini sur DateTimeStyles.RoundtripKind.

Le spécificateur de format standard «O» ou «o» correspond à la chaîne de format personnalisé «aaaa» - «MM» - «jj'T'HH»: «mm»: «ss». «FffffffK» pour les valeurs DateHeure et "aaaa '-' MM '-' jj'T'HH ':' mm ':' ss '.' fffffffzzz" Chaîne de format personnalisé pour les valeurs DateTimeOffset. Dans cette chaîne, les paires de guillemets simples qui délimitent des caractères individuels, tels que les tirets, les deux points et la lettre «T», indiquent que le caractère individuel est un littéral qui ne peut pas être modifié. Les apostrophes n'apparaissent pas dans la chaîne de sortie.

Le spécificateur de format standard O "ou" o "(et la chaîne de format personnalisée" aaaa '-' MM '-' jj'T'HH ':' mm ':' ss '.' FffffffK ") tire parti des trois méthodes que ISO 8601 représente les informations de fuseau horaire pour préserver la propriété Kind des valeurs 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
la source
Parce que cela ne fonctionne pas comme demandé, vous l'avez cité après tout - ce "yyyy'-'MM'-'dd'T'HH':'mm':'ss'.'fffffffzzz" n'est pas le format Zulu.
astrowalker
@astrowalker Cela devrait fonctionner. Il vous a donné plusieurs options dans sa réponse. Il vous suffit d'en choisir un. Dans votre cas (et dans les OP), vous utiliseriez DateTimeKind.Utc pour produire des chaînes avec "z" à la fin (aka "Zulu Format" ou "UTC Time"). Regardez son exemple de sortie pour UTC. Dans mon cas, j'ai utilisé: dtVariable.ToUniversalTime().ToString("o")qui se convertira en "2019-05-26T19:50:34.4400000Z"ou "yyyy-MM-ddTHH:mm:ss.fffffffZ". Remarque: j'ai également testé cela avec la new Date(dtDateString).getTime()méthode Javscript et il analyse correctement la chaîne de date produite par cela.
MikeTeeVee
@MikeTeeVee, je faisais juste remarquer que les solutions fournies ne fonctionneront pas (pour DTO). La manière appropriée est dto.ToUniversalTime().ToString("yyyy'-'MM'-'dd'T'HH':'mm':'ss'.'FFFFFFF'Z'"). Pour mémoire, "o"ajoute juste un décalage, ce n'est pas au format Zulu.
astrowalker
1
Pour ceux qui essaient de faire une transformation de chaîne:$"{DateTime.UtcNow:O}"
Tiago César Oliveira
18
string.Format("{0:yyyy-MM-ddTHH:mm:ss.FFFZ}", DateTime.UtcNow)

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

Arviman
la source
6

Le meilleur format à utiliser est "aaaa '-' MM '-' jj'T'HH ':' mm ':' ss '.' FffK".

Le dernier K sur la chaîne sera changé en «Z» si la date est UTC ou avec le fuseau horaire (+ -hh: mm) si est local. ( http://msdn.microsoft.com/en-us/library/8kb3ddd4.aspx )

Comme LukeH l'a dit, il est bon d'utiliser ToUniversalTime si vous voulez que toutes les dates soient UTC.

Le code final est:

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

Certaines personnes ont souligné que «ToUniversalTime» est quelque peu dangereux en ce sens qu'il peut provoquer des erreurs d'heure involontaires. En développant cela, je donne un exemple plus détaillé d'une solution. L'exemple ici crée une extension de l'objet DateTime qui renvoie en toute sécurité un DateTime UTC où vous pouvez utiliser ToString comme vous le souhaitez….

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
la source
5

Vous souhaitez utiliser la classe DateTimeOffset .

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

désolé j'ai manqué votre formatage d'origine avec les millisecondes

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

Ce code fonctionne pour moi:

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
la source
-3

Essaye ça:

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

Question posée précédemment

Ian P
la source
3
Je n'essaye pas (encore) de l'analyser, j'essaye de l'imprimer.
Grzenio