Wie kann ich DateTime im Web-UTC-Format formatieren?

88

Ich habe eine DateTime, die ich auf " 2009-09-01T00:00:00.000Z" formatieren möchte , aber der folgende Code gibt mir " 2009-09-01T00:00:00.000+01:00" (beide Zeilen):

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

Irgendwelche Ideen, wie es funktioniert?

Grzenio
quelle

Antworten:

158
string foo = yourDateTime.ToUniversalTime()
                         .ToString("yyyy'-'MM'-'dd'T'HH':'mm':'ss'.'fff'Z'");
LukeH
quelle
1
@Downvoter: Möchten Sie uns sagen, was Ihrer Meinung nach mit dieser Antwort falsch ist?
LukeH
12
Dies hat funktioniert, aber .ToUniversalTime () wird Ihr vorhandenes Datum durcheinander bringen, wenn es bereits bei UTC ist, die Variable yourDateTime es jedoch nicht angibt. Am Ende entfernte ich die .ToUniversalTime () und die Daten stimmten dann mit den Erwartungen an beiden Enden überein (Datenbank und Webclient).
Robin Vessey
10
Wenn Ihre Datums- und Uhrzeitangabe bereits eine Weltzeit ist, können Sie .ToUniversalTime()alles aufrufen, was Sie möchten. Dies ändert nichts. - Wenn Sie jedoch einen universellen Zeitwert als Ortszeit gespeichert haben, ändert sich dieser natürlich (aber in diesem Fall haben Sie größere Probleme!) - Wie auch immer, diese Antwort lautet furchtbar. Sie sollten "O"stattdessen die Formatzeichenfolge verwenden, die in der folgenden Antwort angegeben ist.
BrainSlugs83
1
@ BrainSlugs83: Diese "schreckliche" Antwort gibt dem OP tatsächlich das, wonach sie gefragt haben : 2009-09-01T00:00:00.000Z. Die Verwendung des "O" -Spezifizierers würde ihnen etwas anderes geben : 2009-09-01T00:00:00.0000000Z.
LukeH
Dokumentation für die benutzerdefinierte Zeichenfolgenformatierung für DateTime docs.microsoft.com/en-us/dotnet/standard/base-types/…
Mark Hebert
71

Warum nicht einfach den Formatspezifizierer " Round-Trip" ("O", "o") verwenden ?

Der Standardformatbezeichner "O" oder "o" stellt eine benutzerdefinierte Datums- und Zeitformatzeichenfolge dar, die ein Muster verwendet, das Zeitzoneninformationen beibehält und eine Ergebniszeichenfolge ausgibt, die ISO 8601 entspricht. Bei DateTime-Werten dient dieser Formatbezeichner zum Beibehalten des Datums und Zeitwerte zusammen mit der DateTime.Kind-Eigenschaft im Text. Die formatierte Zeichenfolge kann mithilfe der Methoden DateTime.Parse (String, IFormatProvider, DateTimeStyles) oder DateTime.ParseExact zurückgemeldet werden, wenn der Parameter styles auf DateTimeStyles.RoundtripKind festgelegt ist.

Der Standardformatbezeichner "O" oder "o" entspricht dem benutzerdefinierten Format "yyyy" - "MM" - "dd'T'HH": "mm": "ss". "FffffffK" für DateTime-Werte und dem "yyyy '-' MM '-' dd'T'HH ':' mm ':' ss '.' fffffffzzz" benutzerdefinierte Formatzeichenfolge für DateTimeOffset-Werte. In dieser Zeichenfolge geben die Paare von einfachen Anführungszeichen, die einzelne Zeichen begrenzen, wie z. B. die Bindestriche, die Doppelpunkte und der Buchstabe "T", an, dass das einzelne Zeichen ein Literal ist, das nicht geändert werden kann. Die Apostrophe erscheinen nicht in der Ausgabezeichenfolge.

Der Standardformatbezeichner O "oder" o "(und der benutzerdefinierte Formatstring" yyyy "-" MM "-" dd'T'HH ":" mm ":" ss "." FffffffK ") nutzen die drei Möglichkeiten dass ISO 8601 Zeitzoneninformationen darstellt, um die Kind-Eigenschaft von DateTime-Werten beizubehalten:

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
quelle
Da es nicht wie gewünscht funktioniert, haben Sie es doch zitiert - es "yyyy'-'MM'-'dd'T'HH':'mm':'ss'.'fffffffzzz" ist kein Zulu-Format.
Astrowalker
@astrowalker Es sollte funktionieren. Er gab Ihnen in seiner Antwort mehrere Optionen. Sie müssen nur einen auswählen. In Ihrem Fall (und in den OPs) würden Sie DateTimeKind.Utc verwenden, um Zeichenfolgen mit "z" am Ende zu erstellen (auch bekannt als "Zulu Format" oder "UTC Time"). Schauen Sie sich einfach seine Beispielausgabe für UTC an. In meinem Fall habe ich verwendet: dtVariable.ToUniversalTime().ToString("o")das wird in "2019-05-26T19:50:34.4400000Z"oder konvertiert "yyyy-MM-ddTHH:mm:ss.fffffffZ". Hinweis: Ich habe dies auch mit der new Date(dtDateString).getTime()Methode von Javscript getestet und es analysiert die von dieser erzeugte Datumszeichenfolge korrekt.
MikeTeeVee
@ MikeTeeVee, ich habe nur darauf hingewiesen, dass die bereitgestellten Lösungen nicht funktionieren (für DTO). Der geeignete Weg ist dto.ToUniversalTime().ToString("yyyy'-'MM'-'dd'T'HH':'mm':'ss'.'FFFFFFF'Z'"). Für den Datensatz wird nur "o"Offset hinzugefügt, es ist kein Zulu-Format.
Astrowalker
Für diejenigen, die versuchen, eine String-Transformation $"{DateTime.UtcNow:O}"
durchzuführen
17
string.Format("{0:yyyy-MM-ddTHH:mm:ss.FFFZ}", DateTime.UtcNow)

gibt 2017-02-10T08: 12: 39.483Z zurück

Arviman
quelle
6

Das beste Format ist "JJJJ" - "MM" - "TT'T'HH": "MM": "SS". "FffK".

Das letzte K in der Zeichenfolge wird in 'Z' geändert, wenn das Datum UTC ist, oder mit der Zeitzone (+ -hh: mm), wenn es lokal ist. ( http://msdn.microsoft.com/en-us/library/8kb3ddd4.aspx )

Wie LukeH sagte, ist es gut, die ToUniversalTime zu verwenden, wenn Sie möchten, dass alle Daten UTC sind.

Der endgültige Code lautet:

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

Einige Leute haben darauf hingewiesen, dass 'ToUniversalTime' insofern etwas unsicher ist, als es zu unbeabsichtigten falschen Zeitabbrüchen führen kann. Darauf aufbauend gebe ich ein detaillierteres Beispiel für eine Lösung. Das Beispiel hier erstellt eine Erweiterung des DateTime-Objekts, die sicher eine UTC DateTime zurückgibt, in der Sie ToString wie gewünscht verwenden können.

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

Sie möchten die DateTimeOffset- Klasse verwenden.

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

Entschuldigung, ich habe Ihre ursprüngliche Formatierung mit den Millisekunden verpasst

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

Dieser Code funktioniert für mich:

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

Versuche dies:

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

Zuvor gestellte Frage

Ian P.
quelle
3
Ich versuche (noch) nicht, es zu analysieren, ich versuche es auszudrucken.
Grzenio