user1950349
user1950349

Reputation: 5146

How to convert std::chrono::time_point to uint64_t?

I am trying to see whether my data is 120 second (or 2 minutes) old or not by looking at the timestamp of the data so I have below code as I am using chrono package in C++:

uint64_t now = duration_cast<milliseconds>(steady_clock::now().time_since_epoch()).count();
// check for 2 minutes old data
bool is_old = (120 * 1000 < (now - data_holder->getTimestamp()));   

uint64_t value = now;
while (now < data_holder->getTimestamp() + 80 * 1000 
        && now < value + 80 * 1000) {
    std::this_thread::sleep_for(std::chrono::milliseconds(100));
    now = duration_cast<milliseconds>(steady_clock::now().time_since_epoch()).count();
}

In the above code data_holder->getTimestamp() is uint64_t which returns timestamp in milliseconds.

Now when I print out now variable value, I see this 10011360 and when I print out data_holder->getTimestamp() value which is 1437520382241

2015-07-21 16:13:02,530 WARN 0x7f35312d1700 data_check - now value: 10011360 , data holder timestamp: 1437520382241

And from the above data holder timestamp, it doesn't look to be 120 second old data right so I feel something is wrong in my code? Since if I convert that data holder timestamp to actual time (using epoch converter) and then compare it with logs time as shown above it is almost same.

So I decided to use system_clock instead of steady_clock and came up with below code in which I started to use auto instead of uint64_t.

Solution A:

auto now = system_clock::now();
auto dh_ts = system_clock::time_point{milliseconds{data_holder->getTimestamp()}};
bool is_old = (minutes{2} < (now - dh_ts));

Earlier, I was using now variable value as uint64_t instead of auto. Now after the above code, I have something like this in my original code since now is not uint64_t so I am getting compilation error while compiling the code.

uint64_t value = now;
while (now < data_holder->getTimestamp() + 80 * 1000 
        && now < value + 80 * 1000) {
    std::this_thread::sleep_for(std::chrono::milliseconds(100));
    now = duration_cast<milliseconds>(steady_clock::now().time_since_epoch()).count();
}

What is the right way to fix this? I cannot change data_holder->getTimestamp() data type, it has to be uint64_t since other code is also using it.

Here is the error:

error: cannot convert std::chrono::time_point<std::chrono::_V2::system_clock, std::chrono::duration<long int, std::ratio<1l, 1000000000l> > >â to âuint64_t {aka long unsigned int}â in initialization

UPDATE:

Can I use like this instead of using Solution A if everything looks good below?

Solution B:

uint64_t now = duration_cast<milliseconds>(system_clock::now().time_since_epoch()).count();
bool is_old = (120 * 1000 < (now - data_holder->getTimestamp()));

Upvotes: 1

Views: 13154

Answers (2)

Jerry Coffin
Jerry Coffin

Reputation: 490663

At least as I read it, this is sleeping 100 ms at a time, then checking whether it's slept for 2 minutes yet. Then repeating until it reaches the 2 minute point.

It seems to me like it makes a lot more sense to compute the desired time, and sleep until then:

struct foo { 
    time_point<system_clock> time_stamp;

    time_point<system_clock> get_timestamp() { return time_stamp; }
    foo() : time_stamp(system_clock::now()) {}
};

// ...    
foo f;

std::this_thread::sleep_until(f.get_timestamp() + 2m);

This does use the (new in C++14) user defined literal to construct a duration of 2 minutes. If you really need to support an older (C++11) compiler, you'll need to use minutes(2) instead.

As far as the title question goes, I'd say: just say no. Far better to store your time_points as actual time_points than insist on stuffing them into integers, then turn them back into time_points when you need to use them again. It's not at all apparent that this accomplishes anything useful in exchange for the pain.

Upvotes: 2

hdastwb
hdastwb

Reputation: 149

Actually, I would suggest going more in the direction of solution A and converting the rest of your uint64_t times into time_points: the chrono unit system is pretty useful. I would start by defining a helper function to convert from the uint64_t timestamps on your objects to time_points:

using u64_millis = duration<uint64_t, milli>;
static time_point<system_clock, u64_millis> u64_to_time(uint64_t timestamp) {
    return time_point<system_clock, u64_millis>{u64_millis{timestamp}};
}

if your epoch is different than the one for system_clock, this would be the place to fix it. It would probably also work to use milliseconds instead of u64_millis, but the representation type for milliseconds isn't explicitly defined and doing it the above way ensures that the types match up correctly.

Now, the code that you posted becomes something like:

auto now = system_clock::now();
bool is_old = now - u64_to_time(data_holder->getTimestamp()) > minutes{2};

auto value = now;
while (now - u64_to_time(data_holder->getTimestamp()) < seconds{80}
        && now - value < seconds{80}) {
    this_thread::sleep_for(milliseconds{100});
    now = system_clock::now();
}

Upvotes: 0

Related Questions