Як можна відформатувати DateTime до веб-формату UTC?


89

У мене є DateTime, який я хочу відформатувати в " 2009-09-01T00:00:00.000Z", але такий код дає мені " 2009-09-01T00:00:00.000+01:00" (обидва рядки):

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

Будь-які ідеї, як змусити це працювати?

Відповіді:


161
string foo = yourDateTime.ToUniversalTime()
                         .ToString("yyyy'-'MM'-'dd'T'HH':'mm':'ss'.'fff'Z'");

1
@Downvoter: Чи хотіли б ви сказати нам, що, на вашу думку, не відповідає цій відповіді?
LukeH

12
Це спрацювало, але .ToUniversalTime () зіпсує вашу існуючу дату, якщо вона вже в UTC, але змінна yourDateTime її не вказує. У підсумку я видалив файл .ToUniversalTime (), а дати потім вишикувались так, як очікувалося на обох кінцях (база даних та веб-клієнт).
Робін Вессі,

10
Якщо ваш час дати вже є універсальним часом, ви можете зателефонувати .ToUniversalTime()усім, що хочете, це не змінить його. - Однак, якщо у вас є універсальне значення часу, яке зберігається як місцевий час, то, звичайно, воно його змінить (але в такому випадку у вас є більші проблеми!) - У будь-якому випадку, ця відповідь жахливий. "O"Замість цього слід використовувати рядок формату, як зазначено у відповіді нижче.
BrainSlugs83,

1
@ BrainSlugs83: Це «страшний» відповідь на насправді дає О.П. , що вони просили: 2009-09-01T00:00:00.000Z. Використання «O» специфікатор дасть їм що - то інше: 2009-09-01T00:00:00.0000000Z.
LukeH

Документація для власного форматування рядків для DateTime docs.microsoft.com/en-us/dotnet/standard/base-types/…
Марк Геберт,

75

Чому б просто не використовувати специфікатор формату в обидва кінці ("O", "o") ?

Стандартний специфікатор формату "O" або "o" представляє власний рядок формату дати та часу із використанням шаблону, який зберігає інформацію про часовий пояс та випромінює рядок результатів, що відповідає ISO 8601. Для значень DateTime цей специфікатор формату призначений для збереження дати і значення часу разом із властивістю DateTime.Kind у тексті. Відформатований рядок можна проаналізувати назад за допомогою DateTime.Parse (String, IFormatProvider, DateTimeStyles) або DateTime.ParseExact, якщо для параметра стилів встановлено DateTimeStyles.RoundtripKind.

Специфікатор стандартного формату "O" або "o" відповідає рядку користувацького формату "Значення дати і часу" та "yyyy '-' MM '-' dd'T'HH ':' mm ':' ss '.' FffffffK" "yyyy '-' MM '-' dd'T'HH ':' mm ':' ss '.' fffffffzzz" рядок користувацького формату для значень DateTimeOffset. У цьому рядку пари одинарних лапок, які розмежовують окремі символи, такі як дефіси, двокрапки та буква "Т", вказують на те, що окремий символ - це літерал, який не можна змінити. Апострофи не відображаються у вихідному рядку.

Специфікатор стандартного формату O "або" o "(і рядок користувацького формату" yyyy '-' MM '-' dd'T'HH ':' mm ':' ss '.' FffffffK ") використовує три способи: що ISO 8601 представляє інформацію про часовий пояс для збереження властивості Kind значень 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

Оскільки це не працює за запитом, ви все-таки це процитували - "yyyy'-'MM'-'dd'T'HH':'mm':'ss'.'fffffffzzz" це не формат зулу.
astrowalker

@astrowalker Це має спрацювати. У своїй відповіді він дав вам кілька варіантів. Вам потрібно вибрати лише одну. У вашому випадку (і в операційних програмах) ви б використовували DateTimeKind.Utc для створення рядків із "z" в кінці (він же "Zulu Format" або "UTC Time"). Просто подивіться на його приклад виводу для UTC. У моєму випадку я використав: dtVariable.ToUniversalTime().ToString("o")котрий перетвориться на "2019-05-26T19:50:34.4400000Z"або "yyyy-MM-ddTHH:mm:ss.fffffffZ". Примітка: Я також перевірив це за допомогою new Date(dtDateString).getTime()методу Javscript, і він правильно аналізує рядок дати, створений цим.
MikeTeeVee

@MikeTeeVee, я просто вказував, що надані рішення не будуть працювати (для DTO). Відповідний спосіб є dto.ToUniversalTime().ToString("yyyy'-'MM'-'dd'T'HH':'mm':'ss'.'FFFFFFF'Z'"). Для запису, просто "o"додає зміщення, це не формат зулу.
astrowalker

1
Для тих, хто намагається виконати струнну трансформацію:$"{DateTime.UtcNow:O}"
Тіаго Сесар Олівейра

18
string.Format("{0:yyyy-MM-ddTHH:mm:ss.FFFZ}", DateTime.UtcNow)

повертається 2017-02-10T08: 12: 39.483Z


6

Найкращий формат для використання - "рррр" - 'ММ' - 'дд'Т'ХЧ': 'мм': 'ss'. 'FffK ".

Останній K у рядку буде змінено на 'Z', якщо дата UTC або з часовим поясом (+ -hh: mm), якщо локальна. ( http://msdn.microsoft.com/en-us/library/8kb3ddd4.aspx )

Як сказав LukeH, добре використовувати ToUniversalTime, якщо ви хочете, щоб усі дати були UTC.

Остаточний код:

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

6

Деякі люди зазначають, що "ToUniversalTime" є дещо небезпечним, оскільки може спричинити ненавмисне неправильне відображення часу. Розширюючи це, я наводжу більш детальний приклад рішення. Зразок тут створює розширення об’єкта DateTime, яке безпечно повертає UTC DateTime, де ви можете використовувати ToString за бажанням….

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();
    }
}

5

Ви хочете використовувати клас DateTimeOffset .

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

вибачте, я пропустив ваше початкове форматування з мілісекундами

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

5

Цей код працює для мене:

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

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.