In a Delphi (11.3) VCL program, I'm using a method to convert 638563016295520210
ticks to a TDateTime
. I know Delphi works with a TDateTime
from 12/30/1899
and I tried using TTimeSpan.FromTicks()
, but without any success.
Here's the function I'm calling:
function TicksToDateTime(Ticks: Int64): TDateTime; // Ticks input is 638563016295520210
const
TicksPerDay = 864000000000; // Number of ticks in a day
var
Days, RemainingTicks, FractionOfDay: Int64;
BaseDate: TDateTime;
begin
BaseDate := EncodeDate(1, 1, 1); // January 1, 0001
Days := Ticks div TicksPerDay; // Calculate the number of days (638563016295520210 div 864000000000)
RemainingTicks := Ticks mod TicksPerDay; // Calculate the Remaining Ticks
FractionOfDay := RemainingTicks div TicksPerDay; // Convert Remaining Ticks to Fraction of a Day
Result := BaseDate + Days + (RemainingTicks div TicksPerDay); // The Result should equal 07/11/2024 9:33 AM EST.
end;
I'm making the call via:
MyDate := TicksToDateTime(iTicks);
And then formatting the TDateTime
result. The function call is giving me a date result of 05/10/0203
. How do I get the desired result of 07/11/2024 9:33 AM
?
TDateTime
is implemented using a floating-point Double
value, where the date is in the integral portion and the time is in the fractional portion.
div
performs integer division, you can't get a fraction from that. You need to use /
instead, which performs floating-point division.
But, in any case... in comments, you said:
When I input the number of ticks to the datetimetoticks-converter it does convert properly
That is not what I see happen. When I enter your input value 63856301629552021
into that site, it reports 10/05/0203 18:09:22
(May 10 0203 6:09:22pm), not 07/11/2024 09:33:00
(July 11?, November 7? 2024 9:33am) as you are expecting.
Which makes sense, as @AmigoJack commented:
63856301629552021 div 864000000000 = 73907 days = 202 years... Adding 202 years and something to 0001-01-01 is expected to sum up to 0203-01-01 and something.
(of course, his comment isn't taking months and days of each month into account, but you get the idea.)
So, either your input is wrong, or your expectation is wrong (probably both).
According to that site:
Jul 11 2024 9:33 AM = 638562871800000000
Nov 07 2024 9:33 AM = 638665687800000000
Notice your input value is 17 digits, but the values above are both 18 digits, which means your input is missing quite a lot of precision to reach anywhere near the year 2024.
When I use the following code and correct input values, I get the TDateTime
value you are expecting:
uses
System.DateUtils, System.TimeSpan;
function TicksToDateTime(Ticks: Int64): TDateTime;
begin
Result := IncMillisecond(
EncodeDate(1, 1, 1),
Trunc(TTimeSpan.FromTicks(Ticks).TotalMilliseconds)
);
end;
TicksToDateTime(63856301629552021 ) // returns May 10 0203 6:09:22.955 PM
TicksToDateTime(638562871800000000) // returns Jul 11 2024 9:33:00.000 AM
TicksToDateTime(638665687800000000) // returns Nov 07 2024 9:33:00.000 AM
If you don't want to use TTimeSpan
, a minor tweak to your existing code will yield similar1 results:
function MyTicksToDateTime(Ticks: Int64): TDateTime;
const
TicksPerDay = 864000000000;
var
BaseDate: TDateTime;
Days: Int64;
RemainingTicks: Int64;
FractionOfDay: Double; // <--
begin
BaseDate := EncodeDate(1, 1, 1);
Days := Ticks div TicksPerDay;
RemainingTicks := Ticks mod TicksPerDay;
FractionOfDay := RemainingTicks / TicksPerDay; // <--
Result := BaseDate + Days + FractionOfDay;
end;
TicksToDateTime(63856301629552021 ) // returns May 11 0203 5:50:37.045 AM
TicksToDateTime(638562871800000000) // returns Jul 11 2024 9:33:00.000 AM
TicksToDateTime(638665687800000000) // returns Nov 07 2024 9:33:00.000 AM
1: notice that in this case, 63856301629552021
returns May 11 0203 5:50:37.045 AM
instead of May 10 0203 6:09:22.955 PM
as with TTimeSpan
. I'm not sure why the difference, and I don't care to figure it out right now. It has something to do with how FractionOfDay
is being (mis?)calculated. The other two values return the correct result, though.