Преобразование std:: chrono:: Time point в метку времени unix

как я могу получить 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 (00:00:00 UTC 1 января 1970 года).

3 ответов


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

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

Linux:

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

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

окна:

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

Mac OS X:

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

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

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

так хотя и не указано в C++ существует простой и широко переносимый способ получить временную метку 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's time zone) and get the
// number of seconds since your system's 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.


другой вариант-использовать приличную библиотеку дат, такую как Говард объектов по chrono::date. (Говард Объектов был одним из парней, которые работали на C++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);

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


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

static uint64_t getUnixTimeStamp(const std::time_t* t = nullptr)
{
    //if specific time is not passed then get current time
    std::time_t st = t == nullptr ? std::time(nullptr) : *t;
    auto secs = static_cast<std::chrono::seconds>(st).count();
    return static_cast<uint64_t>(secs);
}

преимущество этой функции заключается в том, что значение параметра по умолчанию просто дает вам текущее время. Однако, если вы хотите преобразовать определенное время в метку времени unix, вы также можете это сделать.


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

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

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