Как я могу отформатировать 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")

Есть идеи, как заставить его работать?

Ответы:


160
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

Почему бы просто не использовать описатель формата Round-trip ("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" для значений DateTime и Строка настраиваемого формата для значений DateTimeOffset "yyyy" - 'MM' - 'dd'T'HH': 'mm': 'ss'. 'fffffffzzz'. В этой строке пары одинарных кавычек, разделяющих отдельные символы, такие как дефисы, двоеточия и буква «T», указывают на то, что отдельный символ является литералом, который нельзя изменить. Апострофы не отображаются в выходной строке.

Описатель стандартного формата 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" это не формат Zulu.
astrowalker

@astrowalker Должно работать. В своем ответе он дал вам несколько вариантов. Вам нужно только выбрать один. В вашем случае (и в OP) вы должны использовать 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"добавляет смещение, это не формат Zulu.
astrowalker

1
Для тех, кто пытается преобразовать струны:$"{DateTime.UtcNow:O}"
Тьяго Сезар Оливейра


6

Лучше всего использовать формат «гггг» - «ММ» - «дд'Т'ЧЧ»: «мм»: «сс». '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, которое безопасно возвращает DateTime в формате UTC, где вы можете использовать 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.