Reputation: 4388
Why won't the following function compile, with the error
cannot convert from 'std::chrono::time_point<std::chrono::steady_clock,std::chrono::duration<double,std::nano>>' to 'std::chrono::time_point<std::chrono::steady_clock,std::chrono::steady_clock::duration>'
#include <chrono>
typedef std::chrono::high_resolution_clock::time_point TimePoint;
typedef std::chrono::duration<double, std::ratio<86400>> JulianDays;
TimePoint JulianDaysToUTC(const JulianDays& days)
{
static const JulianDays EquivalentJulianYearInDays(2451545.0);
static const JulianDays LeapSecondCorrection(0.0008);
static const TimePoint CorrectedEpoch = TimePoint() - EquivalentJulianYearInDays + LeapSecondCorrection;
return CorrectedEpoch + days;
}
Note: TimePoint()
was substituted for a function returning a TimePoint
, but that return value is not / should not be relevant.
Modifying it to use an integer duration allows it to compile, but I lose the fractional day portion, which is undesired.
#include <chrono>
typedef std::chrono::high_resolution_clock::time_point TimePoint;
typedef std::chrono::duration<int, std::ratio<86400>> Days;
typedef std::chrono::duration<double, std::ratio<86400>> JulianDays;
TimePoint JulianDaysToUTC(const JulianDays& days)
{
using std::chrono::duration_cast;
static const JulianDays EquivalentJulianYearInDays(2451545.0);
static const JulianDays LeapSecondCorrection(0.0008);
static const TimePoint CorrectedEpoch = TimePoint() - duration_cast<Days>(EquivalentJulianYearInDays) + duration_cast<Days>(LeapSecondCorrection);
return CorrectedEpoch + duration_cast<Days>(days);
}
Upvotes: 3
Views: 2910
Reputation: 218900
The <chrono>
library is designed so that truncation error won't happen implicitly. This is because truncation error can easily happen and often results in an accidental loss of information.
The error message:
cannot convert from
time_point<steady_clock, duration<double,std::nano>>
totime_point<steady_clock, steady_clock::duration>
is saying that an implicit conversion from fractional nanoseconds (double-based) to whole nanoseconds (integral-based) has been attempted but is not allowed. It turns out that every steady_clock::duration
happens to be nanoseconds, though that is not specified.
If truncation is what you desire (as in this case), one can use duration_cast
or time_point_cast
to truncate towards zero. In C++17, floor
, ceil
and round
truncation modes are added.
Here is the most straight-forward way to perform the truncation casts that the library is refusing to do implicitly:
#include <chrono>
typedef std::chrono::high_resolution_clock::time_point TimePoint;
typedef std::chrono::duration<double, std::ratio<86400>> JulianDays;
TimePoint JulianDaysToUTC(const JulianDays& days)
{
static const JulianDays EquivalentJulianYearInDays(2451545.0);
static const JulianDays LeapSecondCorrection(0.0008);
static const TimePoint CorrectedEpoch =
std::chrono::time_point_cast<TimePoint::duration>(
TimePoint() - EquivalentJulianYearInDays + LeapSecondCorrection);
return std::chrono::time_point_cast<TimePoint::duration>(CorrectedEpoch + days);
}
The first cast is necessary because the expression TimePoint() - EquivalentJulianYearInDays + LeapSecondCorrection
has type time_point<high_resolution_clock, duration<double, nano>>
(floating point nanoseconds time_point), and the destination type is a integral-based nanoseconds time_point. Ditto for the second conversion.
auto
could be used to clean this code up a little, and avoid one of the conversions:
#include <chrono>
typedef std::chrono::high_resolution_clock::time_point TimePoint;
typedef std::chrono::duration<double, std::ratio<86400>> JulianDays;
TimePoint JulianDaysToUTC(const JulianDays& days)
{
static const JulianDays EquivalentJulianYearInDays(2451545.0);
static const JulianDays LeapSecondCorrection(0.0008);
static const auto CorrectedEpoch = TimePoint() -
EquivalentJulianYearInDays + LeapSecondCorrection;
return std::chrono::time_point_cast<TimePoint::duration>(CorrectedEpoch + days);
}
Now CorrectedEpoch
is a double-based nanosecond time_point, but that detail is not really important to your algorithm.
Also, Nicol Bolas's comment about the suspicious use of high_resolution_clock
is warranted. Your code may work if you never mix a TimePoint
with a high_resolution_clock::time_point
that came from high_resolution_clock::now()
. However you would be safer to just create your own custom clock with a documented 2000-01-01 12:00:00 UTC epoch. Then any accidental mixing would be caught at compile time.
Upvotes: 3