Search code examples
c++c++11c++-chronogettimeofday

How to get exactly the same result of timeval with C++11 chrono


In my C++ project, there is a very old function, which used the system function of Linux to do some calculation about time.

Here is a picec of code:

struct timeval tv;
gettimeofday(&tv, NULL);
uint32_t seqId = (tv.tv_sec % 86400)*10000 + tv.tv_usec / 100;

* 10000 and / 100 are not wrong, because this piece of code is about to generate a seqId.

Now, I'm trying to use std::chrono of C++11 to replace it. Here is my code:

std::chrono::high_resolution_clock::duration duration_since_midnight() {
    auto now = std::chrono::high_resolution_clock::now();
    std::time_t tnow = std::chrono::high_resolution_clock::to_time_t(now);
    tm *date = std::localtime(&tnow);
    date->tm_hour = 0;
    date->tm_min = 0;
    date->tm_sec = 0;
    auto midnight = std::chrono::system_clock::from_time_t(std::mktime(date));
    return now - midnight;
}
auto res = duration_since_midnight();
auto sec = std::chrono::duration_cast<std::chrono::seconds>(res);
auto mil = std::chrono::duration_cast<std::chrono::milliseconds>(res - sec);
std::cout << sec.count() * 10000 + mil.count() << std::endl;

However, the result is always kind of wrong. For example, the old version may give me 360681491 but my version would give me 360680149. You see they are not exactly the same.

I don't know why. Or it's not possible to do so with std::chrono?


Solution

  • You do not have to stick to the duration types that the library provides. You can define your own that has the representation that you need:

    using tenthmillis = duration<long, ratio<1,10000>>;
    

    Then you can follow up with the following calculation.

    auto now = high_resolution_clock::now().time_since_epoch();
    auto oneDay = duration_cast<tenthmillis>(days{1});
    auto sinceMidnight = duration_cast<tenthmillis>(now) % oneDay.count();
    
    cout << sinceMidnight.count();
    
    

    Note: Add namespace qualifications as required yourself.

    [Update: Instead of high_resolution_clock, choose a clock that uses gettimeofday in its implementation to get results that are comparable to your gettimeofday implementation.]