1

I would like to replace some boost time lines with std::chrono.

*boost::posix_time::ptime myTime( boost::gregorian::date(1960, 1, 1)) As far as I know, Gregorian time is available on C++20. So is there a way to work around this for C++11?

*boost::posix_time::microsec_clock::local_time() and boost::posix_time::microsec_clock::universal_time() I guess I could replace this with high_resolution_clock. But how can I get the local_time() and universal_time() equivalents for std?

*boost::posix_time::time_duration

*boost::system_time const timeout = boost::get_system_time()

EDIT: After reviewing Howaard's question here are some findings:

  1. I converted boost::system_time const timeout=boost::get_system_time() to auto const timeout = std::chrono::system_clock::now() However this gives me the following errors:

    /usr/include/boost/thread/pthread/condition_variable_fwd.hpp:155:31: error: ‘const struct std::chrono::time_point<std::chrono::_V2::system_clock, std::chrono::duration<long int, std::ratio<1, 1000000000> > >’ has no member named ‘is_pos_infinity’ if (wait_duration.is_pos_infinity())

    /usr/include/boost/thread/pthread/condition_variable_fwd.hpp:160:31: error: ‘const struct std::chrono::time_point<std::chrono::_V2::system_clock, std::chrono::duration<long int, std::ratio<1, 1000000000> > >’ has no member named ‘is_special’ if (wait_duration.is_special())

/usr/include/boost/thread/pthread/condition_variable_fwd.hpp:164:50: error: no match for ‘operator+’ (operand types are ‘boost::system_time’ {aka ‘boost::posix_time::ptime’} and ‘const std::chrono::time_point<std::chrono::_V2::system_clock, std::chrono::duration<long int, std::ratio<1, 1000000000> > >’) return timed_wait(m,get_system_time()+wait_duration);

  1. About the conversion from boost::posix_time::microsec_clock::universal_time() to std::chrono::system_clock... Do i have to use a method contained in system_clock()?

  1. Isn't there any way (even hacky way) to convert these two lines:

    boost::posix_time::ptime time_t_epoch(boost::gregorian::date(1970,1,1))

     boost::posix_time::microsec_clock::local_time()
    

to C++11 std::chrono?

1 Answer 1

2

For C++11, I have written a C++20 chrono preview library which is open source. The library is divided roughly in two:

  1. Deals with UTC and calendars.
  2. Deals with time zones.

The first part is header-only and lives in "date/date.h". The second part lives in "date/tz.h" and has an associated source that must be compiled in: date/source/tz.cpp. Here are instructions for doing that.

  • boost::posix_time::ptime myTime( boost::gregorian::date(1960, 1, 1))

This would translate to:

auto myTime = date::sys_days{date::year{1960}/1/1};

In C++20, everywhere you see date:: becomes std::chrono::. And if std::chrono:: scattered everywhere is too irritating for you (it is for me), then a function-local using namespace std::chrono; really cleans things up nicely.

The type of myTime is std::chrono::time_point<std::chrono::system_clock, std::ratio<86400>> (which is why auto is such a useful tool here). In English, that type is a system_clock::time_point but with a precision of days. It represents this date in UTC. You can also think of it as a pointer to the first instant of that date in UTC. For example if you converted it to a system_clock::time_point, then it would point to the midnight where that date begins:

std::chrono::system_clock::time_point myTime = date::sys_days{date::year{1960}/1/1};

If you are willing to bring namespace date::literals into scope you can make this statement slightly more concise:

using namespace date::literals;
auto myTime = date::sys_days{1960_y/1/1};
  • boost::posix_time::microsec_clock::local_time() and boost::posix_time::microsec_clock::universal_time() I guess I could replace this with high_resolution_clock. But how can I get the local_time() and universal_time() equivalents for std?

high_resolution_clock has no portable mapping to a human calendar. It does map to the civil calendar on gcc, but not on LLVM or MSVC. You want to use system_clock for this.

"universal time" in C++ is system_clock. Technically system_clock is UTC excluding leap seconds, but that is true in boost as well. If you really want leap seconds, C++20 provides a way to do that (utc_clock as opposed to system_clock) but this isn't needed as often as you might think.

For universal time at microseconds precision it is:

date::sys_time<std::chrono::microseconds> myTime = date::sys_days{1960_y/1/1};

Note the reuse of the previous API. This is a recurring theme in chrono.

For local time you will need tz.h and tz.cpp.

If you want to specify the time in local time, then simply use date::local_days in place of date::sys_days:

auto myTime = date::local_days{1960_y/1/1};

This is a std::chrono::time_point, but with a "local clock" which is not associated with a specific time zone (not even your computer's local time zone). However you can associate it with a time zone. The time zone can then be used to translate between local_time and sys_time.

The above statement refers to the date 1960-01-01 in some local time zone. Want it in microseconds? Then:

date::local_time<std::chrono::microseconds> myTime = date::local_days{1960_y/1/1};

(note recurrent API pattern)

Now let's get a little more interesting. Let's say you want your computer's local time at 1960-01-01 00:00:00 UTC:

auto myTime_utc = date::sys_days{1960_y/1/1};
auto myTime_local = date::current_zone()->to_local(myTime_utc);

This looks up your computer's local time zone and uses it to map UTC to your local time. The precision here will be seconds because in general the UTC offset is in seconds. If the UTC time had been specified to be microseconds, then the local time would also be microseconds.

using namespace std::literals;
using namespace date::literals;

auto myTime_utc = date::sys_days{1960_y/1/1} + 1us;
auto myTime_local = date::current_zone()->to_local(myTime_utc);

If you instead wanted to know the UTC time point at 1960-01-01 local time then:

auto myTime_local = date::local_days{1960_y/1/1};
auto myTime_utc = date::current_zone()->to_sys(myTime_local);

And for bonus points, if you want the local time somewhere else, that can be done too:

auto myTime_utc = date::sys_days{1960_y/1/1};
auto myTime_local = date::locate_zone("Asia/Tokyo")->to_local(myTime_utc);
  • boost::posix_time::time_duration

This is simply std::chrono::duration which is templated on representation and period. The representation is simply an arithmetic type such as long long or float. The period is a std::ratio<N, D> where N/D is the fraction of a second between ticks of the duration. And there exists type aliases for common durations. For example:

using milliseconds = duration<long long, std::ratio<1, 1000>>;

Additionally clocks, such as system_clock have a "native duration" as a type alias: system_clock::duration. This is usually set to whatever the underlying OS supplies. On Apple it is microseconds, on linux nanoseconds and on Windows 1/10 of microseconds.

Example use:

auto d = 5ms;

d has type std::chrono::milliseconds and a value of 5.

system_clock::duration d = 5ms;

Now d has type system_clock::duration (which varies by platform) and has a value that represents the equivalent of 5 milliseconds.

  • boost::system_time const timeout = boost::get_system_time()

This is

auto const timeout = std::chrono::system_clock::now();

timeout could be used (for example) as an argument in std::this_thread::sleep_until(). Or perhaps more realistically:

auto const timeout = std::chrono::system_clock::now() + 3s;
// ...
std::this_thread::sleep_until(timeout);

Here are more boost examples converted to chrono / date.

Responses to edit

  1. I converted boost::system_time const timeout=boost::get_system_time() to auto const timeout = std::chrono::system_clock::now() However this gives me the following errors:
/usr/include/boost/thread/pthread/condition_variable_fwd.hpp:155:31: error:

You will need to migrate to C++11's std::condition_variable. This should be a relatively easy migration. There is a matching std::mutex and std::unique_lock. The std version of these tools accept std::chrono components for timing as opposed to boost::chrono components. This migration would be even easier if boost would type alias to the std version when available.

  1. About the conversion from boost::posix_time::microsec_clock::universal_time() to std::chrono::system_clock... Do i have to use a method contained in system_clock()?

std::chrono::system_clock has a static member function called now(). And if desired you can store that in a microseconds precision time point:

auto tp = std::chrono::time_point_cast<std::chrono::microseconds>(
    std::chrono::system_clock::now());

If you don't care what precision it is stored as then simply:

auto tp = std::chrono::system_clock::now();
  1. Isn't there any way (even hacky way) to convert these two lines: ...

You could start implementing those parts of C++20 chrono yourself. Some of it is very simple such as just getting local time points:

#include <chrono>

struct local_t {};

template <class Duration>
    using sys_time = std::chrono::time_point<std::chrono::system_clock, Duration>;

template <class Duration>
    using local_time = std::chrono::time_point<local_t, Duration>;

auto const UTC_offset = -std::chrono::hours{5};

template <class Duration>
local_time<Duration>
to_local(sys_time<Duration> tp)
{
    return local_time<Duration>{tp.time_since_epoch() + UTC_offset};
}

local_time<std::chrono::system_clock::duration>
local_now()
{
    return to_local(std::chrono::system_clock::now());
}

int
main()
{
    auto tp_local = local_now();
}

Formatting time_points gets more challenging. But it is all implementable in C++11. Here are efficient public domain calendrical algorithms to get you started. If you go far enough, you will have re-implemented my date/time library and C++20 chrono.

2
  • Thank you for the amazing answer! Your library is great, but unfortunately I am not allowed to use it. I updated the question with some comments based on your answer. Commented Dec 22, 2023 at 15:31
  • Thanks a lot! One last thing. Can your local time implementation be done in a more compact manner? Like a one liner or a single function? Commented Jan 4 at 10:37

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.