Use std::chrono and the date library instead of boost date time
Summary
Use std::chrono and the date library instead of boost date time as internal types of
Rationale
We currently use the boost::date_time
library to manage timepoints (using boost::posix_time::ptime
) and durations (using boost::posix_time::time_duration
. Note that we define BOOST_DATE_TIME_POSIX_TIME_STD_CONFIG
to ensure that boost date time classes are compiled with a nanosecond precision (as a precision of the order of 10-7s is required for some SAR computations). However, when compared to the results of OTB 7.4 that uses ossimplugin to manage timepoints and durations we observed a degradation from 50% to 100% in processing time in some applications (e.g. SAR orthorectification, SARDeburst).
boost::posix_time::ptime
uses 96 bits to store the Unix time when it is compiled with a nanosecond precision, to ensure there is no overflow of the date. On the other end, ossimplugins uses a double
to store the unix time. Because of the way ptime
is implemented, we noticed that differences between two time points is very slow, and about half the processing time of OrthoRectification is spent performing these differences. whereas in ossim plugins the timepoints differences are efficient because double subtraction is not an expensive operation. But note that the ossim implementation is not very precise, because a double is not enough to store the Unix time with a 10-7 precision (this is why we initially choose to use boost instead of an implementation similar to the one of ossimplugin)
This merge request replaces the uses of boost::posix_time
by std::chrono
to manage time in SAR computations. As the chrono library functionalities are quite limited before C++ 20, the date.h
header from the date library. This library was used as a draft for the extension of the chrono standard library in C++ 20. It is licensed under a MIT license and has been integrated as a third party module (OTBDate
).
when templated with a nanosecond precision, std::chrono::time_point stores the unix time as a 64 bit integer. This makes the operations of time much more efficient. Note that storing the time points on a 64 bit integer means that only dates between 1677-09-21 00:12:43.145224192
and 2262-04-11 23:47:16.854775807
are supported (before overflow), which is more than enough for OTB applications.
This merge request also remove the OTB::Metadata::Time
class (which is based on std::tm
) that was used to store dates for optical captors by OTB::Metadata::TimePoint
.
Implementation details
-
otb::MetaData::Duration
is now a wrapper aroundstd::chrono::nanoseconds
-
otb::MetaData::TimePoint
is now a wrapper aroundstd::chrono::time_point<std::chrono::system_clock, InternalDurationType>
As with the previous implementation based on boost date time, the following operators are implemented
- Addition of two
Duration
- Subtraction of two
Duration
- Multiplication between a
Duration
and a scalar - division between a
Duration
and a scalar - ratio between two
Duration
- Addition of a
TimePoint
and aDuration
- Subtraction of a
Duration
from aTimePoint
- comparison (
==
,<
,>
,<=
,>=
) of twoDuration
- comparison (
==
,<
,>
,<=
,>=
) of twoTimePoint
Additionally streaming operator (<<
and >>
) have been implemented for Duration
and TimePoint
. It is also possible to parse a TimePoint
from a string and a format using the function
TimePoint ReadFormattedDate(const std::string & dateStr, const std::string & format = details::timePointFormat)
Supported format are documented here
The implementation from the date
library write the date with the templated precision, and I don't think this is something that can be change with the to_stream
parameters. This is different from the behavior of the boost datetime library. for exemple the same date is written
- "2009-08-10T10:30:08.142149Z" by boost date time
- "2009-08-10T10:30:08.142149000" by date (the Z could be added)
Therefore in the otb::TimePoint::Display
method implementation, the result from to_stream
is post-processed to return the same format as the one used in boost date time.
The implementation of GetModifiedJulianDay
has been modified to perform the computation directly from the internal duration, instead of applying an offset to GetJulianDay
, this modification causes slight numerical differences on some tests because of double error accumulation.
Tests
ioTvDateTest
has been updated with additional unit tests for TimePoint
(the already implemented unit test have not been modified)
A few baselines have been updated because of the differences produced by GetModifiedJulianDay
.
Performances
On develop, an OrthoRectification of a Sentinel 1 product took 438.27s on my computer, with the modification it only took 271,13s. On the release 7.4 the same processing took 235,69s.
Copyright
The copyright owner is CNES and has signed the ORFEO ToolBox Contributor License Agreement.
Check before merging:
- All discussions are resolved
- At least 2
👍 votes from core developers, no👎 vote. - The feature branch is (reasonably) up-to-date with the base branch
- Dashboard is green
- Copyright owner has signed the ORFEO ToolBox Contributor License Agreement
- Optionally, run
git diff develop... -U0 --no-color | clang-format-diff.py -p1 -i
on latest changes and commit