I am using boost::asio::steady_timer m_timer and if I am not mistaken, in order to call m_timer.expires_after(expiration_time_ms);, expiration_time_ms should be a std::chrono::milleseconds variable.
Nevertheless, in my case, I have the expiration time as a double. I would like to know if it is possible to cast a double into std::chrono::milliseconds
The aim is to call
void
setExpirationTime(my_casted_double) {
boost::asio::steady_timer m_timer;
m_timer.expires_after(my_casted_double)
}
One nice trick is to multiply your values with chrono literals:
using namespace std::chrono_literals;
double time = 82.0;
auto t_82ms = time * 1ms;
std::this_thread::sleep_for(t_82ms);
It also works the other way around:
double time = t_82ms / 1s; // time == 0.082
m_timer.expires_after will accept any duration which is convertible to boost::asio::steady_timer::duration it doesn't need to be std::chrono::milliseconds (and if you don't want to discard the fractional milliseconds from your duration you shouldn't be converting to std::chrono::milliseconds).
You can convert your double into a std::chrono::duration as follows:
double milliseconds = 0.1;
std::chrono::duration<double, std::milli> chrono_milliseconds{ milliseconds };
chrono_milliseconds can't however be passed automatically into expires_after as there is no automatic conversion from floating point durations to integer ones. You can fix this with a std::chrono::duration_cast:
m_timer.expires_after(
std::chrono::duration_cast<boost::asio::steady_timer::duration>(chrono_milliseconds));
Related
What is the easiest and elegant way to convert float time in seconds to std::chrono::duration<int64_t, std::nano>?
Is it just converting seconds to nanoseconds and passing to the std::chrono::duration constructor?
I have tried this code:
constexpr auto durationToDuration(const float time_s)
{
// need to convert the input in seconds to nanoseconds that duration takes
const std::chrono::duration<int64_t, std::nano> output{static_cast<int64_t>(time_s * 1000000000.0F)};
return output;
}
But it isn't converting well on many values of the input time_s.
The best way is also the easiest and safest. Safety is a key aspect of using chrono. Safety translates to: Least likely to contain programming errors.
There's two steps for this:
Convert the float to a chrono::duration that is represented by a float and has the period of seconds.
Convert the resultant duration of step 1 to nanoseconds (which is the same thing as duration<int64_t, std::nano>).
This might look like this:
constexpr
auto
durationToDuration(const float time_s)
{
using namespace std::chrono;
using fsec = duration<float>;
return round<nanoseconds>(fsec{time_s});
}
fsec is the resultant type of step 1. It does absolutely no computation, and just changes the type from float to a chrono::duration. Then the chrono engine is used to do the actual computation, changing one duration into another duration.
The round utility is used because floating point types are vulnerable to round-off error. So if a floating point value is close to an integral number of nanoseconds, but not exact, one usually desires that close value.
But std::chrono::round is really a C++17 facility. For C++14, just use one of the free, open-source versions floating around the web (http://howardhinnant.github.io/duration_io/chrono_util.html or https://github.com/HowardHinnant/date/blob/master/include/date/date.h).
I have a double value that represents an epoch time but added the accuracy of a micro second. So a number like this:
double time_us=1628517578.547;
std::chrono::time_point time(time_us);
The above code doesn't;t work as I am getting the following error:
no instance of constructor "time_point" matches the argument list
I need to do this conversion to get the millisecond of the day (number of Milliseconds that passed from the last night).
I plan to use the following code to get the required millisecond:
double sysTOH=time.hour*3600+time.min*60+time.sec+time.usec*1e-6;
What is the best way to achieve this?
std::chrono:: is a lot to write everywhere, so I'm going to assume:
using namespace std::chrono;
time_point is not a concrete type, it is a class template:
template<class Clock, class Duration = typename Clock::duration> class time_point;
This means that you have to supply at least the first template parameter, and in your case, it is best to supply the second as well.
Your input, time_ms, has type double, and represents a count of seconds. So start by creating a type that matches that description:
using ds = duration<double>;
ds is a duration with a rep of double and a period of ratio<1>.
Now it is handy to use a little of C++20 <chrono>. Don't worry, if you don't have C++20, there is a free, open-source, header-only preview of it that works with C++11/14/17.
sys_time<ds> time{ds{time_ms}};
sys_time is a type alias supplied by "date/date.h" for the type:
time_point<system_clock, duration<double>>
I.e. a time_point based on system_clock using your custom duration type ds (double-based seconds).
One first converts the raw double to double-based seconds, and then to a time_point based on those seconds.
Next, it is best to convert to an integral-based time_point to find the time since midnight. Your questions uses microseconds and milliseconds somewhat interchangeably. So I am going to assume milliseconds for everything. Change to microseconds if you need to.
auto tp = round<milliseconds>(time);
This takes the double-based time_point and converts it to an integral-based time_point that counts milliseconds. round is used to avoid round-off error associated with double-based representations. round is part of C++17 and later, but "date/date.h" will supply it for you in C++11/14.
The type of tp is time_point<system_clock, milliseconds>.
Next it is convenient to truncate tp to a precision of days:
auto td = floor<days>(tp);
floor is part of C++17 and later, but "date/date.h" will supply it for you in C++11/14. days is a day-precision duration. td is simply a count of days since the Unix epoch, and has type time_point<system_clock, days>.
One can also think of td as a time point to the beginning of the day. So one can subtract it from tp to get the "time of day", or "time since midnight" UTC:
auto tod = tp - td;
tod has type milliseconds is the value is the number of milliseconds since midnight UTC. If you need midnight defined by some time zone, then there's a little more work to do to take the UTC offset into account. Your question is vague on this point.
Putting it all together:
#include "date/date.h"
#include <chrono>
#include <iostream>
int
main()
{
using namespace date;
using namespace std::chrono;
double time_ms=1628517578.547;
using ds = duration<double>;
sys_time<ds> time{ds{time_ms}};
auto tp = round<milliseconds>(time);
auto td = floor<days>(tp);
auto tod = tp - td;
std::cout << "tod = " << tod << '\n';
}
Output:
tod = 50378547ms
First and foremost, let me say that I just starting using this library yesterday, so my understanding of it is still fairly basic. I'm trying to capture the FPS of a vision processing program I'm creating and output it to a screen using the chrono library. In my case, I need to cast the elapsed time taken after I start a steady_clock to a double (or some other numerical typedef I could treat like a double). I looked through reference documentation and tried working with the duration_cast and time_point_cast functions, but neither of those seem to be what I'm looking for.
My question is; is there any way to simply cast the numerical value of a clock's current state in seconds to a primitive data type?
Any help would be appreciated.
Like this:
#include <chrono>
#include <iostream>
#include <thread>
int main()
{
using namespace std::literals;
// measure time now
auto start = std::chrono::system_clock::now();
// wait some time
std::this_thread::sleep_for(1s);
// measure time again
auto end = std::chrono::system_clock::now();
// define a double-precision representation of seconds
using fsecs = std::chrono::duration<double, std::chrono::seconds::period>;
// convert from clock's duration type
auto as_fseconds = std::chrono::duration_cast<fsecs>(end - start);
// display as decimal seconds
std::cout << "duration was " << as_fseconds.count() << "s\n";
}
example output:
duration was 1.00006s
You could do it using the duration::count function.
For example you could get the duration in the number of milliseconds, and then divide the count by 1000.0 to get the number of seconds as a double.
I am trying to use the follow code:
std::chrono::high_resolution_clock::now();
to get a time stamp, but I need it as a double, but it isn't a support data type, auto works, but I cannot manipulate it.
Your "time stamp" is what the <chrono> library calls a time_point. A time_point is a collection of a clock, and duration. And a duration is a collection of a representation and period.
You have specified two out of these three:
clock == high_resolution_clock
representation == double
period == ?
Your period can be nano (ratio<1, 1000000000>), milli (ratio<1, 1000>), seconds (ratio<1>), minutes (ratio<60>) or any other rational relationship to seconds.
Let's say for example that you wanted a time stamp using double as the representation and seconds as the period. This would look like this:
using clock = std::chrono::high_resolution_clock;
using dsec = std::chrono::duration<double>;
using tps = std::chrono::time_point<clock, dsec>;
tps tp = clock::now();
The time_point emitted by high_resolution_clock::now() will implicitly convert to your time_point using a representation of double and a period of ratio<1>. It will hold fractional seconds since the epoch of high_resolution_clock.
In general, because your destination type has a floating point representation, all time_point source types will implicitly convert to it. To convert in the reverse direction, you would need to use std::chrono::time_point_cast<some-duration>(source-time_point).
If instead you wanted to hold double-based nanoseconds, that would look like:
using clock = std::chrono::high_resolution_clock;
using dns = std::chrono::duration<double, std::nano>;
using tpns = std::chrono::time_point<clock, dns>;
tpns tp = clock::now();
As a guideline, I recommend using either system_clock or steady_clock, but not high_resolution_clock. Use system_clock if your time_point needs to have some relationship with the civil calendar, or needs to maintain meaning across processes. Use steady_clock if your time_point is used only across short durations within the same process.
high_resolution_clock is (de-facto) always an alias to either system_clock or steady_clock. So you might as well use one of the latter, and know what you're getting.
using clock = std::chrono::system_clock;
using dsec = std::chrono::duration<double>;
using tps = std::chrono::time_point<clock, dsec>;
tps tp = clock::now();
std::chrono::high_resolution_clock::now() returns an std::time_point<std::chrono::high_resolution_clock>. Here, you can choose whether you want to express this time point in nanoseconds, microseconds, milliseconds, and so on, using a std::chrono::duration, and ultimately convert this to a double:
std::chrono::time_point<std::chrono::high_resolution_clock> tp = std::chrono::high_resolution_clock::now();
std::chrono::duration<double, std::micro> dur = tp;
double micros = dur.count();
Here you can replace std::micro with whatever resolution you desire.
Checking new stuff from C++, I have found the std::chrono library.
I am wondering if std::chrono::high_resolution_clock could be a good replacement for SDL_GetTicks?
The advantage of going with std::chrono::high_resolution_clock is to keep away from storing time points and time durations in a Uint32. The std::chrono library comes with a wide variety of std::chrono::durations that you should use instead. This will make code more readable, and less ambiguous:
Uint32 t0 = SDL_GetTicks();
// ...
Uint32 t1 = SDL_GetTicks();
// ...
// Is t1 a time point or time duration?
Uint32 d = t1 -t0;
// What units does d have?
vs:
using namespace std::chrono;
typedef high_resolution_clock Clock;
Clock::time_point t0 = Clock::now();
// ...
Clock::time_point t1 = Clock::now();
// ...
// Is t1 has type time_point. It can't be mistaken for a time duration.
milliseconds d = t1 - t0;
// d has type milliseconds
The typed system for holding points in time and time durations has no overhead with respect to just storing things in a Uint32. Except maybe that things will be stored in an Int64 instead. But even that you could customize if you really wanted to:
typedef duration<Uint32, milli> my_millisecond;
You can inspect the precision of the high_resolution_clock with:
cout << high_resolution_clock::period::num << '/'
<< high_resolution_clock::period::den << '\n';
SDL_GetTicks returns milliseconds so it is totally possible to use std::chrono instead, but mind the units conversion necessary. It may not be as simple as SDL_GetTicks. Also, the starting point won't be the same.