Альтернатива mktime в C ++

uint64_t  timestamp_nanoseconds  = 634019142119225390;
time_t result = timestamp_nanoseconds / 1000000000;
struct tm * timeinfo = gmtime(&result);
struct tm dateInfo ;
dateInfo.tm_mday = timeinfo->tm_mday ;
dateInfo.tm_mon = timeinfo->tm_mon ;
dateInfo.tm_year = timeinfo->tm_year ;
dateInfo.tm_hour = 0 ;
dateInfo.tm_min = 0 ;
dateInfo.tm_sec = 0 ;
time_t NoOfSecInDate = mktime ( &dateInfo );

Из входной метки времени в наносекундах мы можем получить дату, как показано в коде, который был установлен в структуре dateInfo. С этого момента нам нужно найти время в секундах, прошедшее с полуночи даты ввода.

Мы получаем ввод как истекшее время в наносекундах с эпохи 1 января 1970 года. Скажем, например, 634019142119225390. Из этого мы извлекаем дату со временем, установленным на 00:00:00, нам нужно найти прошедшее время в целых числах без знака, представляющих прошедшее время в наносекундах. с эпохи Unix 00:00 UTC 1 января 1970 г. с полуночи этой даты.

Решение должно быть для любой данной отметки времени, а не для текущей даты.

В этом приведенном выше коде мы обнаруживаем, что выполнение функции mktime занимает около 64 микросекунд, что является большим временем и не ожидается.

Есть ли у вас какая-либо другая альтернатива функции mktime, которая достигает того же результата, который возвращает истекшее время в секундах с начала эпохи, но с меньшим количеством времени.


person Balan K    schedule 02.08.2017    source источник
comment
Я не понимаю - вы начинаете с time_t, помещаете его в tm, а затем используете mktime, чтобы получить time_t именно из той информации, с которой вы начали? Почему бы просто не использовать result time_t, с которого вы должны были начать?   -  person doctorlove    schedule 02.08.2017


Ответы (2)


Это можно сделать очень эффективно с помощью <chrono> и бесплатной библиотеки даты и времени Говарда Хиннанта с открытым исходным кодом < / а>.

Данный:

uint64_t  timestamp_nanoseconds  = 634019142119225390;

Сформируйте std::chrono::time_point на основе system_clock и nanoseconds. Библиотека даты и времени упрощает это с помощью псевдонима типа шаблона для таких типов:

sys_time<nanoseconds> ts{nanoseconds{timestamp_nanoseconds}};

Затем вы можете усечь эту time_point точность с наносекундной точностью до days точности time_point с помощью:

auto sd = floor<days>(ts);

sd - это system_clock time_point количество дней с начала эпохи (в отличие от наносекунд). Затем вы можете преобразовать sd в year_month_day, и это именно то, на что это похоже: структура {year, month, day} с геттерами для каждого поля:

year_month_day ymd = sd;

И важная часть этого вопроса, вот как вы получаете наносекунды с полуночи:

auto tod = ts - sd;

И если вы хотите, чтобы это было в секундах, это

auto tod = duration_cast<seconds>(ts - sd);

В целом, чтобы перейти от uint64_t подсчета наносекунд к секундам текущего дня (UTC) и времени, это:

auto t0 = steady_clock::now();
sys_time<nanoseconds> ts{nanoseconds{timestamp_nanoseconds}};
auto tod = duration_cast<seconds>(ts - floor<days>(ts));
auto t1 = steady_clock::now();

Учитывая ввод 634019142119225390 и компилируя его с использованием clang в macOS с параметром -O3, это приводит к:

tod == 15942s

и занимает около 200нс.

Эта формулировка будет работать правильно как для положительных , так и для отрицательных входных данных, благодаря использованию floor<days>, а не duration_cast<days>. Например, ввод -1'000'000'000 дает время дня 86399s.

person Howard Hinnant    schedule 04.08.2017

Вы пытаетесь получить время в начале того же дня по всемирному координированному времени. Для этого вы можете просто произвести расчет за секунды:

struct timezone tz = {0, 0};
struct timeval start, end;

gettimeofday(&start, &tz);
uint64_t  timestamp_nanoseconds  = 634019142119225390ULL;
time_t result = timestamp_nanoseconds / 1000000000ULL;
time_t day = result - (result % 86400);
gettimeofday(&end, &tz);

struct timeval dsec;
timersub(&end, &start, &dsec);
printf("calc took %ld sec %ld usec.\n",
   dsec.tv_sec, dsec.tv_usec, s);

printf("UTC: %s",asctime(gmtime(&now)));
printf("Day: %s",asctime(gmtime(&day)));

На это уходит гораздо меньше времени:

calc took 0 sec 1 usec.  total 0.000000
UTC: Sat Feb  3 04:25:42 1990
Day: Sat Feb  3 00:00:00 1990

Если вы хотите получить начало дня в вашем часовом поясе, вы можете добавить смещение к вычислению day.

person stark    schedule 02.08.2017
comment
Из входной метки времени в наносекундах мы можем получить дату, как показано в коде, который был установлен в структуре dateInfo. С этого момента нам нужно найти время в секундах, прошедшее с полуночи даты ввода, а не на текущую дату. - person Balan K; 03.08.2017
comment
Изменено, чтобы показать расчет для данных вашего примера. - person stark; 03.08.2017