I need to convert a TDateTime
to a String
with microsecond precision.
In case of millisecond precision it is possible to use formatting:
DateTimeToString(Result, 'd.m.yyyy hh:nn:ss.zzz', dateTime);
but I need three more digits (microseconds).
It is possible to take the fractional part and divide it by 1/86400/1000000 but I'm looking for more efficient way to convert it.
The accuracy of a date-time varies depending how far away from "zero" you are.
A Delphi TDateTime
is actually an 8-byte floating point Double
, with zero being 12/30/1899 12:00:00 am
.
We can figure out the precision of a TDateTime
by incrementing the floating point datetime by the smallest quantum possible:
function AddQuantumToDateTime(const dt: TDateTime): TDateTime;
var
overlay: Int64 absolute Result;
begin
Result := dt;
overlay := overlay+1;
end;
With this, we can figure out the smallest increment that a TDateTime
can even handle. It varies with the date being used, as the further you are from zero, the larger the quantum amount is:
So for the time being, a DateTime can give you a resolution of about half a microsecond.
While the Windows FILETIME
structure does support a resolution of 100ns, the SYSTEMTIME
structure only supports down to the millisecond:
typedef struct _SYSTEMTIME {
WORD wYear;
WORD wMonth;
WORD wDayOfWeek;
WORD wDay;
WORD wHour;
WORD wMinute;
WORD wSecond;
WORD wMilliseconds;
} SYSTEMTIME, *PSYSTEMTIME;
Microsoft SQL Server's new datetime2(7)
returns datetime strings with up to seven digit (100 ns) of fractional second accuracy:
SELECT CAST('20160802' AS datetime2(6)) AS TheNow
TheNow
==========================
2016-08-02 00:00:00.000000
Your question then is how to convert a TDateTime
to a string that contains microsecond (billionths of a second) precision. You already have your answer:
function DateTimeToStrUs(dt: TDatetime): string;
var
us: string;
begin
//Spit out most of the result: '20160802 11:34:36.'
Result := FormatDateTime('yyyymmdd hh":"nn":"ss"."', dt);
//extract the number of microseconds
dt := Frac(dt); //fractional part of day
dt := dt * 24*60*60; //number of seconds in that day
us := IntToStr(Round(Frac(dt)*1000000));
//Add the us integer to the end:
// '20160801 11:34:36.' + '00' + '123456'
Result := Result + StringOfChar('0', 6-Length(us)) + us;
end;
Where:
DateTimeToStrUs(Now)
Returns:
20160802 11:34:36.482364
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With