I need to convert from a Pascal TDateTime object which is a double value to Unix epoch using c++.
A possible solution is proposed (https://forextester.com/forum/viewtopic.php?f=8&t=1000):
unsigned int UnixStartDate = 25569;
unsigned int DateTimeToUnix(double ConvDate)
{
return((unsigned int)((ConvDate - UnixStartDate) * 86400.0));
}
However, this conversion code produces errors such as:
TDateTime time value = 37838.001388888886 (05.08.2003 02:00)
which converts to Unix epoch 1060041719 (05.08.2003 00:01:59) which is clearly incorrect.
How is it possible to convert this TDateTime value accurately?
The Delphi/C++Builder RTL has a
DateTimeToUnix()
function for this exact purpose.In a
TDateTime
, the integral portion is the number of days fromDecember 30 1899
, and the fractional portion is the time of day from00:00:00.000
. Using raw math involving more than just whole days can be a little tricky, since floating-point math is inaccurate.For instance,
0.001388888886
is not exactly00:02:00
, it is closer to00:01:59.999
. So you are encountering a rounding issue, which is exactly what you have to watch out for.TDateTime
has milliseconds precision, and there are86400000
milliseconds in a day, so.001388888886
is119999.9997504
milliseconds past00:00:00.000
, which is00:01:59
if those milliseconds are truncated to119999
, or00:02:00
if they are rounded up to120000
.The RTL stopped using floating-point arithmetic on
TDateTime
years ago due to subtle precision loss. ModernTDateTime
operations do a round-trip throughTTimeStamp
now to avoid that.Since you are trying to do this from outside the RTL, you will need to implement the relevant algorithms in your code. The algorithm you have shown is how the RTL used to convert a
TDateTime
to a Unix timestamp many years ago, but that is not how it does so anymore. The current algorithm looks more like this now (translated to C++ from the original Pascal):Note my comment in
DateTimeToTimeStamp()
. I'm not sure ifstd::round()
produces exactly the same result as Delphi'sSystem::Round()
for all values. You will have to experiment with it.