Как я могу получить 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 года).
Метка времени Unix определяется как количество секунд с 1 января 1970 года по UTC, за исключением того, что не считаются все секунды. Это несколько нелепо, и нужно задаться вопросом, в чем смысл этого, поэтому я согласен, что это глупый вопрос.
Во всяком случае, давайте посмотрим на некоторые платформы документации для time_t
а также time()
,
time () возвращает время как количество секунд с начала эпохи, 1970-01-01 00:00:00 +0000 (UTC).
POSIX.1 определяет секунды с начала эпохи, используя формулу, которая приближает количество секунд между указанным временем и периодом. Эта формула учитывает тот факт, что все годы, которые делятся поровну на 4, являются високосными, но годы, которые делятся поровну на 100, не являются високосными, если только они не делятся поровну на 400, в этом случае они являются високосными. Это значение не совпадает с фактическим количеством секунд между временем и эпохой из-за високосных секунд и потому, что системные часы не должны синхронизироваться со стандартным эталоном. Намерение состоит в том, чтобы интерпретация секунд, начиная с эпохальных значений, была последовательной; см. POSIX.1-2008 Обоснование A.4.15 для дальнейшего обоснования.
Функция времени возвращает количество секунд, прошедших с полуночи (00:00:00), 1 января 1970 года, всемирного координированного времени (UTC) в соответствии с системными часами.
Функции ctime (), gmtime () и localtime () все принимают в качестве аргумента
значение времени, представляющее время в секундах с начала эпохи (00:00:00
UTC, 1 января 1970 г .;Функции asctime (), ctime (), difftime (), gmtime (), localtime () и mktime ()
функции соответствуют ISO / IEC 9899: 1990 (ISO C90''), and conform to
POSIX.1 ») при условии выбранного местного часового пояса
ISO/IEC 9945-1:1996 (
не содержит таблицу високосных секунд (см. zic (8)).
Аналогичная документация может быть найдена для других систем, таких как AIX, HP-UX, Solaris и т. Д.
Так, хотя не указано в C ++ Существует простой и широко переносимый способ получить метку времени Unix:
auto unix_timestamp = std::chrono::seconds(std::time(NULL));
И если вы хотите количество миллисекунд с 1 января 1970 года по Гринвичу (аналогично, не считая их всех), вы можете сделать это:
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 года по Гринвичу. Если между эпохой системы и 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);
Если вы хотите справиться с високосными секундами, Говард Хиннант также предоставляет библиотека это включает в себя средства для их обработки, а также для анализа баз данных часовых поясов в качестве источника данных о високосных секундах.
Короче говоря, вот функция, которую я использую для получения метки времени Unix (количество секунд с 1 января 1970 года по Гринвичу):
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()
,
Немного сложнее, но, надеюсь, это сработает или, по крайней мере, даст подсказку.