C++中 mktime 的替代品

Alternative to mktime in C++

本文关键字:替代品 mktime C++      更新时间:2023-10-16
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 结构中设置的代码所示。从那时起,我们需要找到从输入日期的午夜开始的经过时间(以秒为单位(。

我们获得自 1970 年 1 月 1 日纪元以来经过的时间(以纳秒为单位(的输入。例如,634019142119225390。从中提取时间设置为 00:00:00 的日期,我们需要找到无符号整数中的经过时间,表示自 1970 年 1 月 1 日 Unix 纪元 00:00 UTC 以来从该日期的午夜开始的经过时间(以纳秒为单位(。

解决方案应针对任何给定时间戳,而不是当前日期。

在上面的代码中,我们发现 mktime 函数大约需要 64 微秒才能完成,这是很多时间,不是预期的

您是否还有其他替代 mktime 函数的方法,它可以实现相同的结果,即返回自 epoch 以来经过的时间(以秒为单位(,但时间更少。

这可以通过<chrono>和Howard Hinnant的免费开源日期时间库非常有效地完成。

鉴于:

uint64_t  timestamp_nanoseconds  = 634019142119225390;

形成基于system_clocknanosecondsstd::chrono::time_point。 日期时间库通过此类类型的模板类型别名使这变得非常容易:

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

接下来,您可以使用以下命令将此纳秒精度time_point截断为days精度time_point

auto sd = floor<days>(ts);

sd是自纪元以来计算天数(与纳秒相对(的system_clocktime_point。 接下来,您可以将sd转换为year_month_day,这正是它听起来的样子:一个{year, month, day}结构,每个字段都有 getter:

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 的输入,并在 macOS 上的 -O3 上使用 clang 编译它,这会导致:

tod == 15942s

大约需要 200ns。

由于使用了floor<days>,而不是duration_cast<days>,该公式将正确适用于正输入和负输入。 例如,输入-1'000'000'000给出一天中86399s的时间。

您正在尝试在同一UTC日期开始时获取时间。 为此,您可以在几秒钟内完成计算:

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中添加偏移量。