1

Following up from here

I am trying to see whether my data is 120 second old or not by looking at the timestamp of the data so I have below small code in my library project which is using std::chrono package:

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

// some logging to print out above values
LOG4CXX_WARN(logger, "data logging, now: " << now << ", data holder timestamp: " << data_holder->getTimestamp() << ", is_old: " << is_old << ", difference: " << (now -         data_holder->getTimestamp()));

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

Now when I print out now variable value, I am seeing this 433425679 and when I print out data_holder->getTimestamp() value which is 1437943796841 and the difference of now and data holder timestamp is coming as 18446742636199180454 as shown below in the logs:

2015-07-26 13:49:56,850 WARN 0x7fd050bc9700 simple_process - data logging, now: 433425679 , data holder timestamp: 1437943796841 , is_old: 1 , difference: 18446742636199180454

Now if I convert data holder timestamp 1437943796841 using epoch converter, I see this:

Your time zone: 7/26/2015, 1:49:56 PM

which is exactly same as the timestamp shown in the logs 2015-07-26 13:49:56,850 WARN so that means my data doesn't look to be 120 second old data. If yes, then why I am seeing is_old value as 1?

It looks like data_holder->getTimestamp() value is coming from this below code in our code base and then we are comparing it for 120 second old data check.

// is this the problem?
struct timeval val;
gettimeofday(&val, NULL);
uint64_t time_ms = uint64_t(val.tv_sec) * 1000 + val.tv_usec / 1000;

Now after carefully reading about various clock implementation in C++, it looks like we should use same clock to do the comparison.

Does my above code in which I am calculating data_holder->getTimestamp() value is the problem? since I am not using steady_clock there so epoch time will be different and that's why I see this issue?

Now my question is - what code should I use then to fix this issue? Should I use steady_clock as well for data_holder->getTimestamp() code? If yes, then what's the right way?

Also same code works fine in Ubuntu 12 box but it doesn't work fine in Ubuntu 14. I am running all statically linked libraries. For Ubuntu 12, code is compiled on Ubuntu 12 running 4.7.3 compiler and for Ubuntu 14, code is compiled on Ubuntu 14 running 4.8.2 compiler.

Community
  • 1
  • 1
user1950349
  • 4,738
  • 19
  • 67
  • 119
  • 4
    [`std::chrono::steady_clock`](http://en.cppreference.com/w/cpp/chrono/steady_clock) is not related to the wall clock time ([`std::chrono::system_clock`](http://en.cppreference.com/w/cpp/chrono/system_clock)). In other words, you can't compare times from the steady clock with times from the system (wall) clock. And `gettimeofday` returns the *wall* clock time. – Some programmer dude Aug 20 '15 at 06:53
  • I see, then what we should do here? Either of these two codes will change I guess right? – user1950349 Aug 20 '15 at 13:24

2 Answers2

2

Use the same clock for both. If your timestamps need to maintain meaning across runs of your application, you must use system_clock, not steady_clock. If your timestamps only have meaning within a single run you can use steady_clock.

steady_clock is like a "stopwatch". You can time stuff with it, but you can't get the current time of day with it.

DataHolder::DataHolder()
    : timestamp_{system_clock::now()}
    {}

system_clock::time_point
DataHolder::getTimestamp()
{
    return timestamp_;
}

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

In C++14 you can shorten this to:

bool is_old = 2min < system_clock::now() - data_holder->getTimestamp();

  • Do use <chrono>.
  • Don't use count() or time_since_epoch() (except for debugging purposes).
  • Don't use conversion factors such as 1000 or 120.

Violation of the guidelines above will turn compile-time errors into run-time errors. Compile-time errors are your friend. <chrono> catches many errors at compile-time. Once you escape the type-safety of <chrono> (e.g. by using count()), you are programming in the assembly language equivalent of time-keeping. And the space/time overhead of <chrono>'s type-safety system is zero.

Howard Hinnant
  • 206,506
  • 52
  • 449
  • 577
1

You should definetely use the same time function for both.

I would recommend changing either the way the getTimestamp() value is created (e.g. by using chrono::system_clock) or the way you compare the timestamp.

The clean way would be to change it like this:

struct timeval val;
gettimeofday(&val, NULL);
uint64_t now = uint64_t(val.tv_sec) * 1000 + val.tv_usec / 1000;
bool is_old = (120 * 1000 < (now - data_holder->getTimestamp()));

Or the other way around

1.Change the way the getTimestamp() value is created

long long time_ms = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now().time_since_epoch()).count();

2.Adjust the compare function

long long now = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now().time_since_epoch()).count();
bool is_old = (120 * 1000 < (now - data_holder->getTimestamp()));
Simon Kraemer
  • 5,700
  • 1
  • 19
  • 49