Avatar ·

Как конвертировать Unix timestamp в DateTime и обратно в C#?

Всем привет! Я начинающий C# разработчик, и у меня возникла проблема с преобразованием Unix timestamp в DateTime и обратно. В моем проекте я получаю от API время в формате Unix timestamp (например, 1678901234). Мне нужно отобразить это время в удобочитаемом формате на UI, а также иногда отправлять обратно на сервер уже сконвертированное значение. Я попробовал написать простую конвертацию, но что-то пошло не так. Вот мой код: ```csharp // Пытаюсь сконвертировать timestamp в DateTime long timestamp = 1678901234; DateTime dateTime = new DateTime(timestamp); Console.WriteLine(dateTime); // Выводит что-то странное... // Пытаюсь сделать обратную конвертацию DateTime now = DateTime.Now; long backToTimestamp = (long)now.Ticks; Console.WriteLine(backToTimestamp); ``` Проблема в том, что: 1. При конвертации timestamp в DateTime я получаю дату 1 января 0001 года, а не ожидаемое 15 марта 2023 года. 2. При обратной конвертации я получаю огромное число, которое не соответствует стандартному Unix timestamp. Я понимаю, что Unix timestamp — это количество секунд, прошедших с 1 января 1970 года (эпохи Unix). Но как правильно реализовать эту конвертацию в C#? Какие классы или методы использовать? И нужно ли учитывать часовые пояса? Буду благодарен за подробное объяснение с работающими примерами кода. Заранее спасибо! <<>>

Правильная конвертация Unix timestamp в DateTime и обратно в C#

Ваша интуиция верна: Unix timestamp — это количество секунд, прошедших с полуночи 1 января 1970 года по UTC. Проблема в вашем коде в том, что конструктор DateTime(long ticks) интерпретирует переданное число как количество 100-наносекундных интервалов (тиков) с 1 января 0001 года, а не как Unix timestamp. Поэтому вы получаете некорректные даты.

Для решения задачи используйте статические методы класса DateTimeOffset или DateTime, начиная с .NET Framework 4.6 и .NET Core. Вот правильные подходы:

1. Конвертация Unix timestamp в DateTime (секунды)

long unixTimestamp = 1678901234; // 15 марта 2023 года, 10:47:14 UTC

// Способ 1: через DateTimeOffset (рекомендуется)
DateTimeOffset dateTimeOffset = DateTimeOffset.FromUnixTimeSeconds(unixTimestamp);
DateTime dateTime = dateTimeOffset.DateTime; // UTC время
Console.WriteLine(dateTime); // 15.03.2023 10:47:14

// Способ 2: через DateTime вручную (для старых версий .NET)
DateTime epoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
DateTime dateTimeManual = epoch.AddSeconds(unixTimestamp);
Console.WriteLine(dateTimeManual); // 15.03.2023 10:47:14

2. Конвертация DateTime в Unix timestamp

DateTime now = DateTime.UtcNow; // Всегда используйте UTC!

// Способ 1: через DateTimeOffset (рекомендуется)
long unixTimestampFromNow = new DateTimeOffset(now).ToUnixTimeSeconds();
Console.WriteLine(unixTimestampFromNow); // текущий timestamp

// Способ 2: вручную (для старых версий .NET)
DateTime epoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
long manualTimestamp = (long)(now - epoch).TotalSeconds;
Console.WriteLine(manualTimestamp);

3. Работа с миллисекундами

Если ваш timestamp содержит миллисекунды (например, 1678901234567), используйте методы с суффиксом Milliseconds:

long unixTimestampMs = 1678901234567;

// Из timestamp в DateTime
DateTimeOffset dto = DateTimeOffset.FromUnixTimeMilliseconds(unixTimestampMs);
DateTime dt = dto.DateTime;

// Из DateTime в timestamp с миллисекундами
long msTimestamp = new DateTimeOffset(dt).ToUnixTimeMilliseconds();

4. Важные рекомендации

  • Всегда работайте с UTC — Unix timestamp по определению не зависит от часового пояса. Используйте DateTime.UtcNow вместо DateTime.Now.
  • Учитывайте Kind — у DateTime есть свойство Kind (Utc, Local, Unspecified). При конвертации из timestamp результат всегда имеет DateTimeKind.Utc.
  • Для локального отображения конвертируйте UTC в локальное время только на этапе вывода: dateTime.ToLocalTime().
  • Проверяйте версию .NET — методы FromUnixTimeSeconds и ToUnixTimeSeconds доступны с .NET Framework 4.6 и .NET Core 1.0.

Полный пример для вашего случая

public static class UnixConverter
{
    private static readonly DateTime Epoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);

    public static DateTime FromUnixTime(long unixTimestamp)
    {
        return Epoch.AddSeconds(unixTimestamp);
    }

    public static long ToUnixTime(DateTime dateTime)
    {
        // Приводим к UTC, если не указано
        if (dateTime.Kind == DateTimeKind.Local)
            dateTime = dateTime.ToUniversalTime();
        else if (dateTime.Kind == DateTimeKind.Unspecified)
            dateTime = DateTime.SpecifyKind(dateTime, DateTimeKind.Utc);

        return (long)(dateTime - Epoch).TotalSeconds;
    }
}

// Использование:
long input = 1678901234;
DateTime result = UnixConverter.FromUnixTime(input);
Console.WriteLine(result); // 15.03.2023 10:47:14

long back = UnixConverter.ToUnixTime(result);
Console.WriteLine(back); // 1678901234

Теперь ваш код будет работать корректно. Главное — помнить про UTC и использовать правильные методы конвертации.

<<>>

Альтернативный подход: использование NodaTime

Если вы работаете с большим количеством операций с датами и временем, рекомендую обратить внимание на библиотеку NodaTime от создателя Joda Time (для Java). Она предоставляет более чистый API и решает многие проблемы, связанные с часовыми поясами.

Установка через NuGet:

Install-Package NodaTime

Пример конвертации:

using NodaTime;

// Unix timestamp в Instant (момент времени)
long unixTimestamp = 1678901234;
Instant instant = Instant.FromUnixTimeSeconds(unixTimestamp);

// Instant в DateTime (локальное время)
DateTimeZone zone = DateTimeZoneProviders.Tzdb["Europe/Moscow"];
ZonedDateTime zoned = instant.InZone(zone);
DateTime localDateTime = zoned.ToDateTimeUnspecified();

// Обратно в Unix timestamp
long back = instant.ToUnixTimeSeconds();

Преимущества NodaTime:

  • Чёткое разделение между "моментом времени" (Instant) и "календарным временем" (LocalDateTime, ZonedDateTime).
  • Встроенная поддержка всех часовых поясов (IANA tzdata).
  • Отсутствие проблем с DateTimeKind.

Это особенно полезно, если ваше приложение работает с пользователями из разных часовых поясов или требует сложных манипуляций с датами.