Как получить дату в формате ISO 8601 из объекта DateTime в C#?
DateTime now = DateTime.Now;
string dateString = now.ToString();
Console.WriteLine(dateString); // Выводит "27.10.2023 14:30:00" - не то!
Пробовал использовать спецификатор "s":
string isoString = now.ToString("s");
Console.WriteLine(isoString); // "2023-10-27T14:30:00" - уже лучше, но нет часового пояса
А ещё я заметил, что если использую `DateTime.UtcNow`, то получаю время без учёта локального смещения. Мне нужно, чтобы дата всегда была с правильным часовым поясом, а для UTC — с буквой "Z" на конце. Пробовал добавлять "K" в формат, но получается каша. Подскажите, как правильно это сделать? Желательно с примерами для разных сценариев: локальное время, UTC, произвольный часовой пояс.
<<Правильное форматирование даты по ISO 8601 в C#
Проблема, с которой вы столкнулись, очень распространена. Дело в том, что стандарт ISO 8601 имеет несколько вариаций, и C# предоставляет гибкие инструменты для каждой из них. Главное — правильно выбрать тип DateTime и спецификатор формата.
Ключевой момент: для корректного отображения часового пояса нужно использовать спецификатор "O" (буква "O", а не ноль) или комбинацию "yyyy-MM-ddTHH:mm:ssK". Разберём оба подхода.
Метод 1: Спецификатор "O" (Round-trip format)
Это самый надёжный способ, рекомендованный Microsoft. Он автоматически учитывает тип DateTime:
- Для
DateTime.UtcNow— добавляет "Z" на конце. - Для
DateTime.Now— добавляет смещение часового пояса (например, "+03:00"). - Для
DateTimeKind.Unspecified— не добавляет ничего.
Пример:
using System;
class Program
{
static void Main()
{
// UTC время
DateTime utcNow = DateTime.UtcNow;
Console.WriteLine(utcNow.ToString("O"));
// Вывод: 2023-10-27T11:30:00.0000000Z
// Локальное время (например, Москва, UTC+3)
DateTime localNow = DateTime.Now;
Console.WriteLine(localNow.ToString("O"));
// Вывод: 2023-10-27T14:30:00.0000000+03:00
// DateTime с явным указанием смещения (через DateTimeOffset)
DateTimeOffset dto = new DateTimeOffset(2023, 10, 27, 14, 30, 0, TimeSpan.FromHours(5));
Console.WriteLine(dto.ToString("O"));
// Вывод: 2023-10-27T14:30:00.0000000+05:00
}
}
Обратите внимание: "O" всегда выводит миллисекунды (7 знаков после запятой). Если они не нужны, используйте следующий метод.
Метод 2: Ручной формат с "K"
Спецификатор "K" отвечает только за часовой пояс, а остальную часть строки вы формируете сами. Это даёт больше контроля:
string format = "yyyy-MM-ddTHH:mm:ssK";
Console.WriteLine(DateTime.UtcNow.ToString(format));
// Вывод: 2023-10-27T11:30:00Z
Console.WriteLine(DateTime.Now.ToString(format));
// Вывод: 2023-10-27T14:30:00+03:00
Если вам нужно убрать миллисекунды или изменить разделитель — это ваш вариант.
Метод 3: Сериализация в JSON
Если вы работаете с JSON (например, через System.Text.Json или Newtonsoft.Json), то даты автоматически сериализуются в ISO 8601. Но можно настроить:
using System.Text.Json;
var options = new JsonSerializerOptions
{
// Гарантирует вывод с часовым поясом
DateTimeFormat = "O"
};
string json = JsonSerializer.Serialize(DateTime.UtcNow, options);
Console.WriteLine(json); // "2023-10-27T11:30:00Z"
Важные замечания
- Всегда используйте
DateTimeOffsetдля работы с произвольными часовыми поясами.DateTimeсKind.Unspecifiedможет привести к ошибкам. - Для строгого соответствия ISO 8601 избегайте локального времени (
DateTime.Now) — используйте UTC или явное смещение. - Если нужно парсить ISO 8601 обратно в
DateTime, используйтеDateTime.ParseExactс тем же форматом.
Альтернативный подход: через DateTimeOffset и ToString
Если вам нужно больше гибкости в отображении (например, убрать миллисекунды или изменить формат времени), рекомендую явно преобразовывать DateTime в DateTimeOffset. Это особенно полезно, когда вы работаете с базами данных или API, где требуется строгий формат.
DateTime now = DateTime.Now;
DateTimeOffset dto = new DateTimeOffset(now);
string isoString = dto.ToString("yyyy-MM-ddTHH:mm:sszzz");
Console.WriteLine(isoString); // 2023-10-27T14:30:00+03:00
// Для UTC:
DateTimeOffset utcDto = DateTimeOffset.UtcNow;
string utcIso = utcDto.ToString("yyyy-MM-ddTHH:mm:ss'Z'");
Console.WriteLine(utcIso); // 2023-10-27T11:30:00Z
Обратите внимание: в последнем примере я использовал 'Z' (в одинарных кавычках), чтобы добавить символ "Z" вручную. Это удобно, если вы точно знаете, что время UTC.
Для .NET 6 и новее
Начиная с .NET 6, появился метод DateTime.ToString("u"), который выводит дату в универсальном формате, но без "Z" на конце:
Console.WriteLine(DateTime.UtcNow.ToString("u"));
// 2023-10-27 11:30:00Z (обратите внимание: пробел вместо T)
Этот формат не совсем ISO 8601, но близок к нему. Используйте его только если API требует именно такой строки.