Reputation: 356
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 );
From the input timestamp in nanoseconds, we can get the date as shown in the code which got set in dateInfo structure. From that point, We need to find elapsed time in seconds from the midnight of the input date.
We get input as elapsed time in nanoseconds since epoch Jan 1 1970. Say for example , 634019142119225390. From that we extract date with time set to 00:00:00 , we need to find the elapsed time in unsigned integer representing elapsed time in nanoseconds since Unix epoch 00:00 UTC on 1st January 1970 from midnight of that date.
Solution should be for any given timestamp and not for a current date.
In this above code , we find that mktime function takes about 64 microseconds to complete which is lot of time and is not expected
Do you have any other alternative to mktime function which achieves the same result that returns the elapsed time in seconds since epoch but with lesser amount of time.
Upvotes: 3
Views: 2160
Reputation: 218830
This can be done highly efficiently with <chrono>
and Howard Hinnant's free, open-source, date-time library.
Given:
uint64_t timestamp_nanoseconds = 634019142119225390;
Form a std::chrono::time_point
based on system_clock
and nanoseconds
. The date-time library makes that very easy with a template type alias for such types:
sys_time<nanoseconds> ts{nanoseconds{timestamp_nanoseconds}};
Next you can truncate this nanosecond-precision time_point
to a days
precision time_point
with:
auto sd = floor<days>(ts);
sd
is a system_clock
time_point
counting days since the epoch (as opposed to nanoseconds). Next you can convert sd
into a year_month_day
, which is exactly what it sounds like: a {year, month, day}
struct with getters for each field:
year_month_day ymd = sd;
And the relevant part for this question, this is how you get nanoseconds since midnight:
auto tod = ts - sd;
And if you want that in terms of seconds, it
auto tod = duration_cast<seconds>(ts - sd);
In all, to go from a uint64_t
count of nanoseconds, to seconds in current day (UTC), and time it, it is:
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();
Given the input of 634019142119225390, and compiling this using clang on macOS at -O3, this results in:
tod == 15942s
and takes about 200ns.
This formulation will work correctly for both positive and negative inputs, due to the use of floor<days>
, as opposed to duration_cast<days>
. For example an input of -1'000'000'000
gives a time of day of 86399s
.
Upvotes: 2
Reputation: 13189
You are trying to get the time at the start of the same UTC day. To do that, you can just do the calculation in seconds:
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)));
This takes much less time:
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
If you want to get the start of the day in your local timezone you can add an offset to the calculation of day
.
Upvotes: 0