For C++11, I have written a C++20 chrono preview library which is open source. The library is divided roughly in two:
- Deals with UTC and calendars.
- 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
- 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.
- 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();
- 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_point
s 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.