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.001388888886is 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.TDateTimehas milliseconds precision, and there are86400000milliseconds in a day, so.001388888886is119999.9997504milliseconds past00:00:00.000, which is00:01:59if those milliseconds are truncated to119999, or00:02:00if they are rounded up to120000.The RTL stopped using floating-point arithmetic on
TDateTimeyears ago due to subtle precision loss. ModernTDateTimeoperations do a round-trip throughTTimeStampnow 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
TDateTimeto 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.