Подтвердить что ты не робот

Преобразовать std:: chrono:: time_point в unix timestamp

Как я могу получить std::chrono::duration с фиксированной даты? Мне нужно это преобразовать std::chrono::time_point в временную метку unix.

Вставить код в XXX

auto unix_epoch_start = XXX;
auto time = std::chrono::system_clock::now();
auto delta = time - unix_epoc_start;
auto timestamp = std::chrono::duration_cast<std::chrono::milliseconds>(delta).count();

Я знаю, что time_point имеет метод time_since_epoch(), но он не гарантирует, что это то же самое, что и unix epoch (00:00:00 UTC 1 января 1970 года).

4b9b3361

Ответ 1

Временная метка unix определяется как количество секунд с 1 января 1970 UTC, за исключением не считая всех секунд. Это несколько смешно, и нужно задаться вопросом, в чем дело, поэтому я согласен, что это глупый вопрос.

В любом случае, рассмотрим документацию на платформе для time_t и time().

Linux:

time() возвращает время как количество секунд с момента Epoch, 1970-01-01 00:00:00 +0000 (UTC).

POSIX.1 определяет секунды с эпохи с использованием формулы, которая приближается к числу секунд между указанным временем и Эпохой. Эта формула учитывает факты, что все годы, которые равномерно делятся на 4, являются високосными годами, но годы, которые равномерно делятся на 100, не являются високосными годами, если они также равномерно не делятся на 400, и в этом случае они являются високосными годами. Это значение не совпадает с фактическим числом секунд между временем и эпохой, из-за прыжковых секунд и потому, что системные часы не требуются для синхронизации со стандартной ссылкой. Цель состоит в том, чтобы интерпретация секунд со времен Эпохи была последовательной; см. POSIX.1-2008 Обоснование A.4.15 для дальнейшего обоснования.

Windows:

Функция времени возвращает количество секунд, прошедших с полуночи (00:00:00), 1 января 1970 года, скоординированное универсальное время (UTC), в соответствии с системными часами.

Mac OS X:

Функции ctime(), gmtime() и localtime() принимают за аргумент      значение времени, представляющее время в секундах со времен Эпохи (00:00:00      UTC, 1 января 1970 года;

Asctime(), ctime(), difftime(), gmtime(), localtime() и mktime()      функции, соответствующие ISO/IEC 9899: 1990 (ISO C90''), and conform to ISO/IEC 9945-1:1996 ( POSIX.1 ''), предоставили выбранный локальный часовой пояс      не содержит таблицу скачка (см. zic (8)).

Аналогичная документация может быть найдена для других систем, таких как AIX, HP-UX, Solaris и т.д.

Итак, хотя на С++ не указан простой и широко переносимый способ получить временную метку Unix:

auto unix_timestamp = std::chrono::seconds(std::time(NULL));

И если вам нужно несколько миллисекунд с 1 января 1970 UTC (аналогично не считая их всех), вы можете сделать это:

int unix_timestamp_x_1000 = std::chrono::milliseconds(unix_timestamp).count();

Просто помните, что эти значения не являются реальными, поэтому вы не можете в общих чертах использовать временные метки unix в арифметике. Например, вычитание временных меток unix не дает вам точное количество секунд между временами. Или если вы сделали что-то вроде:

std::chrono::steady_clock::now() - unix_timestamp;

вы не получили бы точку времени, фактически соответствующую 1970-01-01 00: 00: 00 + 0000.


Как Энди Проулл предлагает вам сделать что-то глупое:

// 1 Jan 1970 (no time zone)
std::tm c = { 0, 0, 0, 1, 0, 70, 0, 0, -1};

// treat it as 1 Jan 1970 (your system time zone) and get the
// number of seconds since your system epoch (leap seconds may
// or may not be included)
std::time_t l = std::mktime(&c);

// get a calender time for that time_point in UTC. When interpreted
// as UTC this represents the same calendar date and time as the
// original, but if we change the timezone to the system TZ then it
// represents a time offset from the original calendar time by as
// much as UTC differs from the local timezone.
std::tm m = *std::gmtime(&l);

// Treat the new calendar time as offset time in the local TZ. Get
// the number of seconds since the system epoch (again, leap seconds
// may or may not be counted).
std::time_t n = std::mktime(&m);

l -= (n-l); // subtract the difference

l должен теперь представлять (неправильное) количество секунд с 1 января 1970 UTC. До тех пор, пока между эпохой системы и 1 января 1970 года (системный часовой пояс) не будет никаких прыжковых секунд или в течение равного промежутка времени в другом направлении от эпохи системы, тогда любые считанные секунды прыжка должны отменить и l будет неправильным в том, как неверные временные метки unix.


Другой вариант - использовать приличную библиотеку даты, такую ​​как Howard Hinnant chrono::date. (Ховард Хиннант был одним из парней, которые работали в библиотеке С++ 11 <chrono>.)

auto now = system_clock::now();
sys_days today = time_point_cast<days>(now);
system_clock::time_point this_morning = today;

sys_days unix_epoch = day(1)/jan/1970;
days days_since_epoch = today - unix_epoch;

auto s = now - this_morning;

auto tz_offset = hours(0);
int unix_timestamp = (days_since_epoch + s + tz_offset) / seconds(1);

Если вы хотите обрабатывать секунды прыжка, Говард Хиннант также предоставляет библиотеку, которая включает в себя средства для их обработки, а также для разбора баз данных часовых поясов, источник для двухскатных данных.

Ответ 2

Короче говоря, вот функция, которую я использую, чтобы получить временную метку Unix (миллисекундный счет с 1 января 1970 UTC):

static uint64_t getUnixTimeStamp(std::time_t* t = nullptr)
{
    std::time_t st = std::time(t);
    auto millies = static_cast<std::chrono::milliseconds>(st).count();
    return static_cast<uint64_t>(millies);
}

Ответ 3

Вы можете использовать mktime() для преобразования нужной даты, закодированной в структуре tm, в локальное значение time_t.

Если вам нужно время UTC, используйте gmttime(), чтобы преобразовать это значение time_t в структуру UTC tm и выяснить из вывода, который вы получаете, структура tm дает желаемый UTC time_t при вводе в mktime().

Немного сложный, но, надеюсь, он будет работать или хотя бы дать подсказку.