Разбираем Unix Timestamp в C#: от метки времени до DateTime и обратно

Онлайн-тренажер Python для начинающих

Изучайте Python легко и без перегрузки теорией. Решайте практические задачи с автоматической проверкой, получайте подсказки на русском языке и пишите код прямо в браузере — без необходимости что-либо устанавливать.

Начать курс

Вступление: Почему Unix Timestamp — это не просто число

Каждый разработчик, работающий с API, базами данных или логами, рано или поздно сталкивается с Unix timestamp. Это целое число (или число с плавающей точкой), которое обозначает количество секунд, прошедших с 1 января 1970 года 00:00:00 UTC — так называемой эпохи Unix (Unix epoch).

Но когда вы видите в ответе сервера число 1719878400, ваш мозг не может сразу сказать: «Ага, это 2 июля 2024 года». Нам нужно преобразовать его в привычный DateTime. И наоборот — сохранить дату в виде метки для передачи.

На Stack Overflow вопрос «How can I convert a Unix timestamp to DateTime and vice versa?» набрал сотни тысяч просмотров. Это значит, что даже опытные C#-разработчики иногда путаются в нюансах. В этой статье мы не просто дадим готовые рецепты, но и заглянем под капот: разберём, как устроены DateTime, DateTimeOffset, тики и временные зоны.

Что такое Unix Timestamp на самом деле?

Прежде чем писать код, давайте договоримся о терминах. Unix timestamp — это количество секунд (иногда миллисекунд) с полуночи 1 января 1970 года по UTC. Важно: это абсолютный момент времени, не зависящий от часового пояса. Именно поэтому его так удобно использовать в распределённых системах.

В C# мы работаем с двумя основными типами:

  • DateTime — классический тип, который может быть как в UTC, так и в локальном времени (свойство Kind).
  • DateTimeOffset — более современный тип, который явно хранит смещение от UTC. Рекомендуется для новых проектов.

Под капотом DateTime хранит количество тиков (100-наносекундных интервалов) с 1 января 0001 года. А Unix timestamp — это просто количество секунд с 1970 года. Чтобы перейти от одного к другому, нужно вычислить разницу между этими двумя эпохами.

Конвертация Unix Timestamp в DateTime (и обратно) — базовые методы

Начиная с .NET Framework 4.6 и .NET Core, в C# появились встроенные методы, которые делают жизнь проще. Давайте посмотрим на них.

1. Из Unix timestamp (секунды) в DateTime

Самый простой способ — использовать DateTimeOffset.FromUnixTimeSeconds(). Он возвращает DateTimeOffset, который затем можно преобразовать в DateTime.

long unixTimestamp = 1719878400; // 2 июля 2024, 00:00:00 UTC

// Получаем DateTimeOffset
DateTimeOffset dateTimeOffset = DateTimeOffset.FromUnixTimeSeconds(unixTimestamp);

// Преобразуем в DateTime (UTC)
DateTime utcDateTime = dateTimeOffset.UtcDateTime;

Console.WriteLine(utcDateTime); // 02.07.2024 0:00:00

Если вам нужно локальное время (например, для отображения пользователю), используйте dateTimeOffset.LocalDateTime. Но будьте осторожны: локальное время зависит от настроек сервера или компьютера.

2. Из DateTime в Unix timestamp

Обратное преобразование — через метод ToUnixTimeSeconds() у DateTimeOffset.

DateTime utcDateTime = new DateTime(2024, 7, 2, 0, 0, 0, DateTimeKind.Utc);

// Создаём DateTimeOffset с явным указанием UTC
DateTimeOffset dateTimeOffset = new DateTimeOffset(utcDateTime);

long unixTimestamp = dateTimeOffset.ToUnixTimeSeconds();

Console.WriteLine(unixTimestamp); // 1719878400

Критически важно: всегда указывайте DateTimeKind.Utc при создании DateTime, который вы собираетесь конвертировать. Если этого не сделать, DateTimeOffset будет считать, что время локальное, и вы получите неверный timestamp — со сдвигом на ваш часовой пояс.

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

Иногда timestamp передаётся в миллисекундах (например, из JavaScript). Для этого есть FromUnixTimeMilliseconds() и ToUnixTimeMilliseconds().

long unixMs = 1719878400000; // 2 июля 2024, 00:00:00 UTC

DateTimeOffset dateTimeOffset = DateTimeOffset.FromUnixTimeMilliseconds(unixMs);
DateTime utcDateTime = dateTimeOffset.UtcDateTime;

// Обратно
long backToMs = new DateTimeOffset(utcDateTime).ToUnixTimeMilliseconds();
Console.WriteLine(backToMs); // 1719878400000

Как это работает под капотом? Разбираем тики и эпоху

Теперь давайте заглянем глубже. Внутри DateTimeOffset.FromUnixTimeSeconds() делает примерно следующее:

  1. Вычисляет количество тиков, соответствующее Unix epoch (1 января 1970 года, UTC).
  2. Умножает переданное количество секунд на TimeSpan.TicksPerSecond (10 000 000 тиков в секунде).
  3. Прибавляет это к базовому значению эпохи.

Вот как это можно написать вручную для понимания:

public static DateTime UnixTimeStampToDateTime(long unixTimeStamp)
{
    // Unix epoch в тиках
    long epochTicks = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc).Ticks;
    // Прибавляем тики из секунд
    long totalTicks = epochTicks + unixTimeStamp * TimeSpan.TicksPerSecond;
    return new DateTime(totalTicks, DateTimeKind.Utc);
}

public static long DateTimeToUnixTimeStamp(DateTime dateTime)
{
    // Приводим к UTC, чтобы избежать сдвига
    DateTime utcDateTime = dateTime.ToUniversalTime();
    long epochTicks = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc).Ticks;
    return (utcDateTime.Ticks - epochTicks) / TimeSpan.TicksPerSecond;
}

Этот код наглядно показывает, что никакой магии нет — просто арифметика с тиками. Но именно понимание этой механики спасает от ошибок, когда вы работаете с разными часовыми поясами или нестандартными эпохами.

Типичные ошибки и как их избежать

На Stack Overflow полно вопросов от разработчиков, которые получают неверное время. Вот три самые частые проблемы:

  • Забыли указать DateTimeKind.Utc. Если вы создаёте DateTime через new DateTime(2024, 7, 2, 0, 0, 0), его Kind = Unspecified. При конвертации в timestamp вы получите значение, смещённое на ваш часовой пояс. Всегда используйте DateTimeKind.Utc или DateTime.SpecifyKind().
  • Путаница между секундами и миллисекундами. Если вы ожидаете секунды, а получаете миллисекунды (или наоборот), время уедет на 1000 порядков. Проверяйте формат данных от API.
  • Игнорирование DateTimeOffset. Многие разработчики до сих пор используют

Блоги

Рекомендаций по книгам