-1

I'm trying to display the difference between high resolution time points in a string like 00:00:00. My problem is that the time is +1 hour when i print it.

#include <chrono>
#include <ctime>
#include <iostream>
#include <thread>

using namespace std;
using namespace chrono;

int main(int argc, char **argv) {
    auto start = high_resolution_clock::now();
    this_thread::sleep_for(seconds(1));
    auto stop = high_resolution_clock::now();
    auto result = stop - start;
    time_t t = duration_cast<seconds>(result).count();
    cout << ctime(&t) << endl;
    return EXIT_SUCCESS;
}

This prints

Thu Jan 1 01:00:01 1970

While i expect it to print

Thu Jan 1 00:00:01 1970

Yet the following prints 1:

cout << (int) duration_cast<seconds>(result).count() << endl;

Maybe it has something to do with the timezone? Any help is appreciated!

T.C.
  • 133,968
  • 17
  • 288
  • 421
fonZ
  • 2,428
  • 4
  • 21
  • 40
  • I haven't used `ctime` in a while, but [the documentation](http://en.cppreference.com/w/cpp/chrono/c/ctime) seems to indicate the time is converted using `localtime`. – Retired Ninja Oct 08 '14 at 22:05
  • localtime returns a struct tm*. I could edit the time but i think it should be correct and not adding 1 hour like it does now. – fonZ Oct 08 '14 at 22:17
  • 1
    If you don't want the time zone to be used, then perform the conversion using a function that doesn't use the time zone, perhaps `gmtime` or any of the other alternatives. – Retired Ninja Oct 08 '14 at 22:22
  • @RetiredNinja woaw, gmtime saves me! i tried and get the expected output, thanks a lot man. Write an answer with it and ill accept it. – fonZ Oct 08 '14 at 22:33
  • hey @fonZ, I updated my answer. You should be able to go further with this one. – Wug Oct 09 '14 at 00:48

1 Answers1

1

After discussing in the comments exactly what you were after, I came up with this:

size_t MkTimestamp(char *output, size_t size)
{
    milliseconds ms = duration_cast<milliseconds>(system_clock::now().time_since_epoch());
    seconds s = duration_cast<seconds>(ms);
    time_t ctime = (time_t) s.count();
    tm components;
    size_t return_value = 0;

    if (!localtime_r(&ctime, &components)) return 0;
    if ((return_value = strftime(output, size, "%F %T:XXX", &components)) == 0) return 0;

    int ms_d1 = ms.count() / 100 % 10, ms_d2 = ms.count() / 10 % 10, ms_d3 = ms.count() % 10;
    output[return_value - 3] = ms_d1 + '0';
    output[return_value - 2] = ms_d2 + '0';
    output[return_value - 1] = ms_d3 + '0';
    return return_value;
}

In short, you give it a character buffer and its size, and it writes a timestamp to it (if the buffer is too small, it returns zero, otherwise it returns the total number of characters it wrote, including the null terminator). If you wanted this timestamp as a std::string, you could use the std::string slice constructor:

char buffer[64];
string timestamp(buffer, MkTimestamp(buffer, sizeof buffer));

The string constructor will read until the null terminator if MkTimestamp succeeds, and will produce an empty string if it fails. You could probably consolidate this step into MkTimestamp if you wanted to.

This is different from your first try in the following way:

  • Since you're trying to produce a timestamp, you're better off using absolute, rather than relative, time.
  • Since we want to use absolute time, we must use system_clock, because this is the only clock that actually gives time_point values that can be meaningfully converted into time_t values that the old C family functions will accept. (Sometimes, these two clocks have the same epoch, or are even the same clock. But not always.)
  • I picked a different time format. You can change that if you want, it won't be hard. I highly recommend that you keep the millisecond placeholders in the format string, so you don't have to do any length tests as long as strftime succeeds.

Credit where credit is due (other stackoverflow answers that I referenced while writing this answer)

Original answer:

Here's an ideone with your code. (Notice that the issue you describe does not occur.) Also, you're missing #include <thread>.

That aside, the documentation for ctime() indicates that its argument is expected to be a calender date. You're passing it an interval of one second, which is more or less meaningless by itself. You're probably right that it's showing exactly one hour off because of a time zone interpretation issue.

I can't answer any better without more details about what you're actually trying to do.

Community
  • 1
  • 1
Wug
  • 12,956
  • 4
  • 34
  • 54
  • There wasn't one before the edit, when I started writing the answer. – Wug Oct 08 '14 at 22:14
  • i know ... but i thought that the people reading this post would understand that this belongs in a program that has a main ... so i added it. – fonZ Oct 08 '14 at 22:15
  • as for what i'm trying to do, im trying to print a string representation of the elapsed time. 00:00:01 and not 01:00:01. The 1 hour is what is bothering me, because it only 1 second elapsed and the conversion to time_t is legal as far as i know. – fonZ Oct 08 '14 at 22:16
  • If all you want is elapsed time, then you shouldn't be trying to print it with a function that doesn't handle elapsed times. Use your second method. – Wug Oct 08 '14 at 22:17
  • So for you it prints 00:00:00? On that ideone i see it prints correctly? – fonZ Oct 08 '14 at 22:20
  • I didn't run it locally. Why can't you just use `(int) duration_cast(result).count()`? – Wug Oct 08 '14 at 22:24
  • Because i need a timestamp, i need to show millis micros and nanos, so it would be a long string of numbers to read if we talk about a couple of seconds or even minutes. That's why i'm trying to make it readable. – fonZ Oct 08 '14 at 22:26
  • Hold on a while and I'll get something working that's closer to what you need. – Wug Oct 08 '14 at 23:25