Jak mogę sformatować DateTime na internetowy format UTC?

89

Mam DateTime, który chcę sformatować na „ 2009-09-01T00:00:00.000Z”, ale poniższy kod daje mi „ 2009-09-01T00:00:00.000+01:00” (obie linie):

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

Jakieś pomysły, jak to działa?

Grzenio
źródło

Odpowiedzi:

160
string foo = yourDateTime.ToUniversalTime()
                         .ToString("yyyy'-'MM'-'dd'T'HH':'mm':'ss'.'fff'Z'");
LukeH
źródło
1
@Downvoter: Czy chcesz nam powiedzieć, co Twoim zdaniem jest nie tak z tą odpowiedzią?
LukeH
12
To zadziałało, ale .ToUniversalTime () zepsuje istniejącą datę, jeśli jest już w UTC, ale zmienna yourDateTime jej nie określa. Skończyło się na usunięciu .ToUniversalTime (), a następnie daty były zgodne z oczekiwaniami na obu końcach (baza danych i klient sieciowy).
Robin Vessey,
10
Jeśli Twoja data i godzina jest już czasem uniwersalnym, możesz dzwonić do .ToUniversalTime()wszystkiego, co chcesz, nie zmieni tego. - Jeśli jednak masz uniwersalną wartość czasu zapisaną jako czas lokalny, to oczywiście ją zmieni (ale w takim przypadku masz większe problemy do rozwiązania!) - W każdym razie ta odpowiedź brzmi straszny. Zamiast tego należy użyć ciągu "O"formatu określonego w odpowiedzi poniżej.
BrainSlugs83
1
@ BrainSlugs83: ta „straszna” odpowiedź faktycznie daje OP co prosili: 2009-09-01T00:00:00.000Z. Korzystanie z „O” specyfikator by dać im coś innego: 2009-09-01T00:00:00.0000000Z.
LukeH
Dokumentacja dotycząca niestandardowego formatowania ciągów dla daty i godziny docs.microsoft.com/en-us/dotnet/standard/base-types/ ...
Mark Hebert
75

Dlaczego po prostu nie użyć specyfikatora formatu Round-trip („O”, „o”) ?

Specyfikator formatu standardowego „O” lub „o” reprezentuje niestandardowy ciąg formatu daty i godziny przy użyciu wzorca, który zachowuje informacje o strefie czasowej i emituje ciąg wynikowy zgodny z normą ISO 8601. W przypadku wartości DateTime ten specyfikator formatu jest przeznaczony do zachowania daty i wartości czasu wraz z właściwością DateTime.Kind w tekście. Sformatowany ciąg można przeanalizować z powrotem przy użyciu metody DateTime.Parse (String, IFormatProvider, DateTimeStyles) lub DateTime.ParseExact, jeśli parametr styles jest ustawiony na DateTimeStyles.RoundtripKind.

Specyfikator formatu standardowego „O” lub „o” odpowiada niestandardowemu ciągowi formatu „yyyy” - 'MM' - 'dd'T'HH': 'mm': 'ss'. „FffffffK” dla wartości DateTime i „rrrr '-' MM '-' dd'T'HH ':' mm ':' ss '.' fffffffzzz" niestandardowy ciąg formatu dla wartości DateTimeOffset. W tym ciągu pary pojedynczych cudzysłowów oddzielające poszczególne znaki, takie jak łączniki, dwukropki i litera „T”, wskazują, że dany znak jest literałem, którego nie można zmienić. Apostrofy nie pojawiają się w ciągu wyjściowym.

Specyfikator formatu standardowego O ”lub„ o ”(i„ yyyy ”- 'MM' - 'dd'T'HH': 'mm': 'ss'. 'FffffffK" niestandardowy ciąg formatu) wykorzystuje trzy sposoby że ISO 8601 reprezentuje informacje o strefie czasowej, aby zachować właściwość Kind wartości 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
źródło
Ponieważ nie działa zgodnie z oczekiwaniami, zacytowałeś go w końcu - "yyyy'-'MM'-'dd'T'HH':'mm':'ss'.'fffffffzzz" to nie jest format Zulu.
astrowalker
@astrowalker Powinno działać. W swojej odpowiedzi dał ci wiele opcji. Musisz tylko wybrać jedną. W twoim przypadku (i OP) użyłbyś DateTimeKind.Utc do utworzenia ciągów znaków z „z” na końcu (inaczej „Format Zulu” lub „Czas UTC”). Spójrz tylko na jego przykładowe wyjście dla UTC. W moim przypadku użyłem: dtVariable.ToUniversalTime().ToString("o")który przekonwertuje na "2019-05-26T19:50:34.4400000Z"lub "yyyy-MM-ddTHH:mm:ss.fffffffZ". Uwaga: przetestowałem to również za pomocą new Date(dtDateString).getTime()metody JavaScript i poprawnie analizuje utworzony przez to ciąg daty.
MikeTeeVee
@MikeTeeVee, właśnie wskazałem, że dostarczone rozwiązania nie będą działać (dla DTO). Właściwy sposób to dto.ToUniversalTime().ToString("yyyy'-'MM'-'dd'T'HH':'mm':'ss'.'FFFFFFF'Z'"). Dla przypomnienia, po prostu "o"dodaje przesunięcie, to nie jest format Zulu.
astrowalker
1
Dla tych, którzy próbują dokonać transformacji strun:$"{DateTime.UtcNow:O}"
Tiago César Oliveira
18
string.Format("{0:yyyy-MM-ddTHH:mm:ss.FFFZ}", DateTime.UtcNow)

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

arviman
źródło
6

Najlepszym formatem do użycia jest „rrrr” - 'MM' - 'dd'T'HH': 'mm': 'ss'. 'FffK ".

Ostatnie K w ciągu zostanie zmienione na „Z”, jeśli data to UTC lub strefa czasowa (+ -hh: mm), jeśli jest lokalna. ( http://msdn.microsoft.com/en-us/library/8kb3ddd4.aspx )

Jak powiedział LukeH, dobrze jest użyć ToUniversalTime, jeśli chcesz, aby wszystkie daty były UTC.

Ostateczny kod to:

string foo = yourDateTime.ToUniversalTime()
                         .ToString("yyyy'-'MM'-'dd'T'HH':'mm':'ss'.'fffK");
Carlos Beppler
źródło
6

Niektórzy ludzie zwracają uwagę, że „ToUniversalTime” jest nieco niebezpieczne, ponieważ może powodować niezamierzone nieprawidłowe wyświetlanie czasu. Rozwijając to, podaję bardziej szczegółowy przykład rozwiązania. Przykład tutaj tworzy rozszerzenie do obiektu DateTime, które bezpiecznie zwraca UTC DateTime, w którym można użyć ToString zgodnie z potrzebami….

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
źródło
5

Chcesz użyć klasy DateTimeOffset .

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

przepraszam, że przegapiłem twoje oryginalne formatowanie z milisekundami

var stringDate = date.ToString("yyyy'-'MM'-'dd'T'HH':'mm':'ss'.'fff'Z'");
Nick Berardi
źródło
5

Ten kod działa dla mnie:

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
źródło
-3

Spróbuj tego:

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

Wcześniej zadane pytanie

Ian P
źródło
3
Nie próbuję go analizować (jeszcze), próbuję go wydrukować.
Grzenio