0

This is a quite trivial question. But I couldn't find a trivial answer for this.

I have a timestamp string with microsecond precision, say, 20:38:42.444491. How do I convert this into a proper time object so that I can use it in time comparisons etc...

I was trying to use the date lib by HowardHinnant. However I am not sure how to use it only with a timestamp.

e.g.

#include <iostream>
#include "date.h"

using namespace std;

// This works fine
chrono::system_clock::time_point makeDateTime(const string& s) {
    istringstream in{s};
    chrono::system_clock::time_point tp;
    in >> date::parse("%d/%m/%y %T", tp);
    return tp;
}

// This always returns epoch. How to fix this ?
chrono::system_clock::time_point makeTime(const string& s) {
    istringstream in{s};
    chrono::system_clock::time_point tp;
    in >> date::parse("%T", tp);
    return tp;
}

int main() {
    auto a = makeDateTime("30/03/09 16:31:32.121567");
    cout << a.time_since_epoch().count() << endl;   // 1238430692121567000

    auto b = makeTime("16:31:32.121567");
    cout << b.time_since_epoch().count() << endl;   // 0
    return 0;
}

As shown, I can correctly parse a date-time stamp. But I need to know how to handle it if I only have a time (without a date).

Anubis
  • 6,995
  • 14
  • 56
  • 87
  • 2
    If you won't use a library, then you're going to have to do the manual work: parse the text into numbers, convert those numbers into integers, and do some multiplication. – Nicol Bolas Nov 17 '20 at 19:47
  • duration, generated with helpers such as std::chrono::microseconds. See https://en.cppreference.com/w/cpp/chrono/duration and scroll down to "Helper types" – Kenny Ostrom Nov 17 '20 at 20:34
  • Possible duplicate: https://stackoverflow.com/a/21021900/2193968 – Jerry Jeremiah Nov 17 '20 at 22:17
  • @JerryJeremiah thanks for the suggestion, but I don't find this to be a duplicate. Please see the updated question. – Anubis Nov 18 '20 at 08:59

1 Answers1

2

With just a time, you've got a couple of options. But you should definitely not put "just a time" into a system_clock::time_point. The reason for this is that system_clock::time_point has a specific meaning: This measures the time since (or before) 1970-01-01 00:00:00 UTC, excluding leap seconds.

To be fair, this meaning is absent in C++11/14/17, and is only specified in C++20. However all implementations followed this convention in C++11/14/17.

You could store "time of day" in a duration such as microseconds. Then in your code you simply interpret this duration as time elapsed since midnight, where you get to define "midnight" (local midnight? UTC? etc.).

std::chrono::microseconds
makeTime(std::string s)
{
    using namespace std;
    using namespace std::chrono;
    istringstream in{move(s)};
    microseconds tp;
    in >> date::parse("%T", tp);
    return tp;
}

The above solution is simple, and that is good. But it is possible that this "time of day" could be accidentally mixed up with some other duration that doesn't mean "time of day" in a way that would cause logic errors in your program.

To make the above more type-safe, you could create a "time of day" clock:

struct time_of_day
{
    using duration   = std::chrono::microseconds;
    using rep        = duration::rep;
    using period     = duration::period;
    using time_point = std::chrono::time_point<time_of_day>;
    static constexpr bool is_steady = false;

    static
    time_point
    now()
    {
        using namespace date;
        using namespace std::chrono;
        auto t_sys = floor<microseconds>(system_clock::now());
        return time_point{t_sys - floor<days>(t_sys)};
    };
};

time_of_day::time_point
makeTime(std::string s)
{
    using namespace std;
    using namespace std::chrono;
    istringstream in{move(s)};
    microseconds d;
    in >> date::parse("%T", d);
    return time_of_day::time_point{d};
}

Above I've defined midnight as UTC just to simplify the demonstration.

The time_of_day solution isn't necessarily better. The programmer should decide if the extra complexity cost justifies the type safety benefit.

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