my problem in short: TDateTime A
(03.09.2014 13:40) - TDateTime B
(03.09.2014 13:40) = -1
I have two TDateTime values which i want to compare, first i used the =
operator to check if they are the same but after a few tests i realized that this is not working in my case. The confusion in this is that it works great the most time but sometimes not.
I get one value out of the LastWriteTime
attribute from an existing file and the other value is from a MySQL database.
Here is some code:
TDateTime a := FileList[loop].Lastwritetime.AsUTCDateTime; // TDateTime from MySQL
TDateTime b := GetLastwritetimeUtc(Sourcedirectory); // TDateTime from my local file
if (CompareDateTime(a, b) = 0) then
begin
// do some stuff.
end;
Now as mentioned before this easy code is working most of the time but for some TDateTime
values i get a negative result which should mean that my TDateTime
value from the MySQL database is earlier then my local file TDateTime
value.
So i started debugging:
double aTicks := a; // MySQL TDateTime
double bTicks := b; // Local file TDateTime
this provides me the days passed since 30.12.1899 and the decimal values the time.
Example values:
// a = 02.09.2014 11:42:01
// b = 02.09.2014 11:42:01
// aTicks = 41884,4875115741
// bTicks = 41884,4875153356
The decimals which are not same should be milliseconds or not (starting after xxxx,4875)?
Now if i compare them (e.g. CompareDateTime(a,b)
or a = b
) i do not get 0
/true
(i do not compare the aTicks
and bTicks
values).
Do i have to make changes in my way i get the local file TDateTime
(at the moment i am using the WinAPI, the GetLastWriteTimeUTC
did not provide me the correct UTC time)?
I think it is not really a hard problem but i have no idea how to solve this. Does the `` TDateTime
store the milliseconds hidden? In the debugging mode i do not see any milliseconds and i do not know how to get this value out of my TDateTime
(using Delphi XE2).
Here are some extra details about my project
I get the TDateTime b
value this way
function GetLastwritetimeUtc(source: String): TDateTime;
var
fad: TWin32FileAttributeData;
SystemTime: TSystemTime;
lastwritetimeUtc: TDateTime;
begin
GetFileAttributesEx(PWideChar(source),GetFileExInfoStandard,@fad);
FileTimeToSystemTime(fad.ftLastWriteTime, SystemTime);
lastwritetimeUtc := SystemTimeToDateTime(SystemTime);
result := lastwritetimeUtc;
end;
If a file from the MySQL database is "newer" i replace it and set the LastWriteTime
from my MySQL TDateTime a
attribute this way: SetLastWriteTimeUTC(a)
(and my TDateTime
values from the MySQL (a) do not have any milliseconds value). So the problem should not occure again but it does.
The TDateTime
value on my MySQL database is from this
XSDateTime c := DateTimeToXSDateTime(GetLastwritetimeUtc(sourceDirectory));
// i send this via WCF service to the MySQL database and store it in a `TDateTime` column (which does not include milliseconds)
I hope this is enough information and not too much.
Best regards,
Niclas
UPDATE:
The code does "the same" as my main program, as i said above the wrong DateTime comparision does not trigger all the time only on some files (in my case the $Default10.dsk).
uses
SysUtils,
Soap.SoapHttpTrans,
DateUtils,
Windows,
System.IOUtils,
Soap.XSBuiltIns;
var
fad: TWin32FileAttributeData;
SystemTime: TSystemTime;
lastwritetimeUtcA: TDateTime;
lastwritetimeUtcB: TDateTime;
sourceFileA: string;
sourceFileB: string;
lastwritetimeXS: TXSDateTime;
begin
while True do
begin
sourceFileA := 'Path to a file on your computer no matter which';
sourceFileB := 'Path to another file on your computer no matter which';
//GetLastWriteTime from local file
GetFileAttributesEx(PWideChar(sourceFileA),GetFileExInfoStandard,@fad);
FileTimeToSystemTime(fad.ftLastWriteTime, SystemTime);
lastwritetimeUtcA := SystemTimeToDateTime(SystemTime);
//Set the localfile lastwritetime to the theoretical mySQL file
// in my main program there does not exist a mySQL file (only a value of TDateTime in the TDateTime column of my database where i store the lastwritetime from the local files
TFile.SetLastWriteTimeUtc(sourceFileB, lastwritetimeUtcA);
//Get the LastWriteTime from theoretical mySQL file
// in my main program i get the lastwritetime value from the MySQL database via WCF that is the reason for the convertion of XSDateTime.AsUTCDateTime and DateTimeToXSDateTime
GetFileAttributesEx(PWideChar(sourceFileB),GetFileExInfoStandard,@fad);
FileTimeToSystemTime(fad.ftLastWriteTime, SystemTime);
lastwritetimeUtcB := SystemTimeToDateTime(SystemTime);
//Convert lastwritetime to XSDatetime - how i do it in my program
lastwritetimeXS := DateTimeToXSDateTime(lastwritetimeUtcB);
{Convert it back to DateTime}
lastwritetimeUtcB := lastwritetimeXS.AsUTCDateTime;
//Compare them
if lastwritetimeUtcA = lastwritetimeUtcB then
Writeln('Same time')
else
writeln('Not same time');
Sleep(500);
end;
end;
If you want to compare two TDateTime
values and match to the second, ignoring millisecond differences, use SecondsBetween
from the DateUtils
unit:
program Project1;
uses
SysUtils, DateUtils;
var
dtOne, dtTwo: TDateTime;
begin
dtOne := 41884.4875115741;
dtTwo := 41884.4875153356;
if SecondsBetween(dtOne, dtTwo) = 0 then
WriteLn('Dates the same without MS')
else
WriteLn('Not the same dates.');
ReadLn;
end.
There are similar functions for other differences, such as DaysBetween
, MinutesBetween
, and MilliSecondsBetween
if you need to match to other resolutions. Here's a utility function that works for various resolutions (exact match, day, hour, minute, or second):
type
TDiffResolution = (tdrExact, tdrDay, tdrHour, tdrMin, tdrSec);
function IsSameDateTime(dValOne, dValTwo: TDateTime;
const Resolution: TDiffResolution = tdrSec): Boolean;
begin
case Resolution of
tdrExact: Result := MillisecondsBetween(dValOne, dValTwo) = 0;
tdrDay: Result := IsSameDay(dValOne, dValTwo);
tdrHour: Result := HoursBetween(dValOne, dValTwo) = 0;
tdrMin: Result := MinutesBetween(dValOne, dValTwo) = 0;
tdrSec: Result := SecondsBetween(dValOne, dValTwo) = 0;
else
raise Exception.CreateFmt('Invalid resolution value (%d) provided.',
[Ord(Resolution)]);
end;
end;
Sample use:
dtOne := 41884.4875115741;
dtTwo := 41884.4875153356;
if IsSameDateTime(dtOne, dtTwo, tdrSec) then
WriteLn('Dates are the same.')
else
WriteLn('Dates are different.');
ReadLn;