Convert File Time To Julian Date in Delphi - delphi

I have a problem getting file modified time as julian date. My Delphi 2010 looks like this:
AHandle := FindFirstFile(PChar('C:\*'), FindData);
if (AHandle <> INVALID_HANDLE_VALUE) then
begin
repeat
if (FindData.dwFileAttributes And FILE_ATTRIBUTE_DIRECTORY = 0) then
ModifJulianDate := FileTimeToJulianDate(FindData.ftLastWriteTime);
until Not FindNextFile(AHandle, FindData);
end;
The problem is: FileTimeToJulianDate() returned result has one hour offset, ie. if the file's modified time is 10:01, this code returns 9:01!!
How can I fix this?

The functionality that you are looking for, assuming your answer is accurate, is most easily implemented using FileTimeToLocalFileTime.
function UTCFileTimeToLocalDateTime(const UTCFileTime: TFileTime): TDateTime;
var
LocalFileTime: TFileTime;
LocalSystemTime: TSystemTime;
begin
if not FileTimeToLocalFileTime(UTCFileTime, LocalFileTime) then
RaiseLastOSError;
if not FileTimeToSystemTime(LocalFileTime, LocalSystemTime) then
RaiseLastOSError;
Result := SystemTimeToDateTime(LocalSystemTime);
end;
Or if you prefer to use SystemTimeToTzSpecificLocalTime then do so like this:
function UTCFileTimeToLocalDateTime(const UTCFileTime: TFileTime): TDateTime;
var
UTCSystemTime, LocalSystemTime: TSystemTime;
begin
if not FileTimeToSystemTime(UTCFileTime, UTCSystemTime) then
RaiseLastOSError;
if not SystemTimeToTzSpecificLocalTime(nil, UTCSystemTime, LocalSystemTime) then
RaiseLastOSError;
Result := SystemTimeToDateTime(LocalSystemTime);
end;

With the help of LU RD & the code posted here, I managed to get what I wanted, in case someone need something like this, here's my code:
function GetDateFileModified(UTCTime : TFileTime{FindData : TWin32FindData}) : TDateTime;
// Return the file modified date as a string in local time
var
GMTsystemTime : Windows.TSystemTime;
LocalSysTime : Windows.TSystemTime;
TimeZone : Windows._TIME_ZONE_INFORMATION;
begin
Result := 0;
// Get Timezone Information
GetTimeZoneInformation(TimeZone);
// UTCTime := FindData.ftLastWriteTime;
if FileTimeToSystemTime(UTCTime, GMTsystemTime) then
begin
SystemTimeToTzSpecificLocalTime(#TimeZone, GMTsystemTime, LocalSysTime);
Result := SystemTimeToDateTime(LocalSysTime);
end;
end;

Related

GetDateFileModified for Daylight Savings Time

function DateTimeToFileTime(FileTime: TDateTime): TFileTime;
var
LocalFileTime, Ft: TFileTime;
SystemTime: TSystemTime;
begin
Result.dwLowDateTime := 0;
Result.dwHighDateTime := 0;
DateTimeToSystemTime(FileTime, SystemTime);
SystemTimeToFileTime(SystemTime, LocalFileTime);
LocalFileTimeToFileTime(LocalFileTime, Ft);
Result := Ft;
end;
function ExtractShortDate(ATimeIn: TDateTime): string;
// Convert DateTime to short date string
begin
Result := FormatDateTime('mm/dd/yyyy', ATimeIn);
end;
function ExtractTime(ATimeIn: TDateTime): string;
// Convert DateTime to am/pm time string
begin
Result := FormatDateTime('hh:mm AM/PM', ATimeIn);
end;
function GetDateFileModified(AFileName: string): string;
// Return the file modified date as a string in local time
var
SR: TSearchRec;
UTCTime: Windows.TFileTime;
GMTST: Windows.TSystemTime;
LocalST: Windows.TSystemTime;
ModifyDT: TDateTime;
TZ: Windows._TIME_ZONE_INFORMATION;
begin
Result := '';
if FindFirst(AFileName, faAnyFile, SR) = 0 then
begin
UTCTime := SR.FindData.ftLastWriteTime;
if FileTimeToSystemTime(UTCTime, GMTST) then
begin
// Get Timezone Information
if GetTimeZoneInformation(TZ) <> 0 then
if SystemTimeToTzSpecificLocalTime(#TZ, GMTST, LocalST) then
begin
ModifyDT := SystemTimeToDateTime(LocalST);
Result := ExtractShortDate(ModifyDT) + ' ' + ExtractTime(ModifyDT);
end
else
begin
TaskMessageDlg('Unable To Convert Time', 'Unable to convert SystemTime To LocalTime',
mtInformation, [mbOk], 0);
Result := '';
exit;
end;
end
else
begin
TaskMessageDlg('Unable To Convert Time', 'Unable to convert FileTime To SystemTime',
mtInformation, [mbOk], 0);
Result := '';
exit;
end;
end
else
TaskMessageDlg('File Not Found', ExtractFileName(AFileName) + ' does not exist.',
mtInformation, [mbOk], 0);
FindClose(SR);
end;
The original code posted did not return the correct time. The original code was replaced with working code so that others may find this beneficial.
Update: The code provides the correct time now thanks to all that assisted.
The problem is highlighted in the MSDN docs for FileTimeToLocalFileTime:
FileTimeToLocalFileTime uses the current settings for the time zone and daylight saving time. Therefore, if it is daylight saving time, this function will take daylight saving time into account, even if the time you are converting is in standard time. You can use the following sequence of functions as an alternative.
FileTimeToSystemTime / SystemTimeToTzSpecificLocalTime / SystemTimeToFileTime
You need to use the three functions specified whenever you look at a file after a daylight savings change that was created before the change (but this method of course also works when you and the file creation are both on the same side of the daylight savings change).

Inverse function of FormatDateTime

I am looking for a function to reverse any string (YYYYMDD,YY/MM/DD,YYMMDD,...) created by the function FormatDateTime to datetime.
example
I have a string-date in format YYYYMMDDcreated by FormatDateTime
mydatestr:=FormatDateTime('YYYYMMDD',Mydate);
now how I can convert mydatestr to DateTime again?
UPDATE
these functions
function StrToDate(const S: string): TDateTime; overload;
function StrToDate(const S: string;
const FormatSettings: TFormatSettings): TDateTime; overload;
function StrToDateTime(const S: string): TDateTime; overload;
function StrToDateTime(const S: string;
const FormatSettings: TFormatSettings): TDateTime; overload;
do not support passing a string with the format to convert.
I am looking something like this
Mydatetime:=InvFormatDatetime('20091225','yyyymmdd');
or
Mydatetime:=InvFormatDatetime('20090108','yyyyddmm');
It is quite easy with existing solution, StrToDateFmt function in rxDateutil.pas unit from RX package, which can be downloaded here: http://sourceforge.net/projects/rxlib/
EDIT:
Mentioned above function and StrToDateFmt from rxDateutil.pas are doing exactly what you expect, converting string to datetime using specified string mask, the code is too large to be included as this unit contains also other date functions, some of them required for converting string to date.
Example of use:
Result := StrToDateFmtDef('MM/DD/YYYY', '11/11/2011', Now);
Note: Unfortunately, as pointed out by Martien in this answer's comments, this solution will not work for cases where the date includes no date separator. However, I'm going to leave the answer up for anyone that may find it useful regardless.
I liked Tuncay's answer but there were a couple of problems with it. I'd have left a comment but I don't have enough reputation points.
So, here's the corrected version of Tuncay's answer (amending "TFormatSetting" missing an "s" and specified the format settings date separator):
function AnyStringToDate(fmt, dt: String) : TDateTime;
var
fs : TFormatSettings;
Begin
fs := TFormatSettings.Create;
fs.DateSeparator := '-';
fs.ShortDateFormat := fmt;
result := StrToDateDef(dt, 0, fs);
End;
Identical to Tuncay's answer, AnyStringToDate can be used as follows:
mydate := AnyStringToDate('YYYY-MM-DD', '2015-01-20');
Without using any external library, you can do something like:
function AnyStringToDate(fmt, dt: String) : TDateTime;
var
fs : TFormatSettings;
Begin
fs := TFormatSettings.Create;
fs.ShortDateFormat := fmt;
result := StrToDateDef(dt, 0, fs);
End;
and then use it like:
mydate := AnyStringToDate('YYYY-MM-DD', '2015-01-20');
I havent compiled this, but the idea simple.
You could use StrToDateFmt function of JvJCLUtils unit belonging to JEDI Code Library
in your case :
Function InvFormatDatetime ( dateString :String; dateFormat :String ) : TDateTime;
begin
Result := JvJCLUtils.StrToDateFmt ( dateFormat, dateString );
end;
Did you check StrToDate and StrToDateTime ?
I know its too late but just for interest sake, with Delphi XE6 onwards you can now do the following
uses
System.DateUtils;
var
dt: TDateTime;
begin
dt := ISO8601ToDate('20190408');
end.
dt will now be 2019/04/08
Function InvFormatDatetime (Cadena:String; Formato:String) : TDateTime;
Var
PosD, PosM, PosY : Integer;
sD, sM, sY : String;
begin
sd := '0';
sm := '0';
sy := '0';
If Length(Cadena) = Length(Formato) Then
Begin
Formato := UpperCase(Formato);
PosD := Pos('D',Formato);
PosM := Pos('M',Formato);
PosY := Pos('Y',Formato);
sd := Copy(Cadena,PosD,2);
sm := Copy(Cadena,PosM,2);
if Length(Cadena) = 6 then
begin
sy := Copy(Cadena,PosY,2);
if StrToInt(sy) > 50 then
sy := '19'+sy
else
sy := '20'+sy;
end
else
sy := Copy(Cadena,Posy,4);
End;
Result := EncodeDate(StrToInt(sY),
StrToInt(sM),
StrToInt(sD));
End;
greetings

Convert a DevExpress TcxFilterOperatorKind to and from a string?

Here is a codesnippet I use to get filtertype operator from a filter in a DevExpress grid:
OperatorKindToStr is used to extract operatorkind from a filter as string and store it in a xml-file.
StrToOperatorKind is used to convert back a string from xml to set an operatorkind in a filter.
const
CUSTFILTER_FILTERITEM = 'FilterItem';
function OperatorKindToStr(const aOperatorKind: TcxFilterOperatorKind): string;
begin
Result := 'foEqual';
case aOperatorKind of
foEqual: Result := 'foEqual';
foNotEqual: Result := 'foNotEqual';
foLess: Result := 'foLess';
foLessEqual: Result := 'foLessEqual';
// Plus a boring list of other constants
end;
function StrToOperatorKind(const aOpKindStr: string): TcxFilterOperatorKind;
begin
Result := foEqual;
if aOpKindStr = 'foNotEqual' then
Result := foNotEqual
else if aOpKindStr = 'foLess' then
Result := foLess
else if aOpKindStr = 'foLessEqual' then
Result := foLessEqual
else if aOpKindStr = 'foGreater' then
Result := foGreater
else if aOpKindStr = 'foGreaterEqual' then
Result := foGreaterEqual
// Plus a boring list of other if-else
end;
procedure UseStrToOperatorKind(const aFilterItem: IXmlDomElement);
begin
if aFilterItem.nodeName = CUSTFILTER_FILTERITEM then
begin // It is an FilterItem
vStr := VarToStr(aFilterItem.getAttribute(CUSTFILTER_COLPROP)); // Get the columnname
vOperatorKind := StrToOperatorKind(aFilterItem.getAttribute(CUSTFILTER_ITEMOPERATOR));
end;
procedure UseOperatorKindToStr(const aFilterItem: TcxCustomFilterCriteriaItem);
var
vStr: String;
begin
if Supports(TcxFilterCriteriaItem(aFilterItem).ItemLink, TcxGridColumn, GridCol) then
vStr := OperatorKindToStr(TcxFilterCriteriaItem(aFilterItem).OperatorKind);
end;
Apparently I want the StrToOperatorKind and OperatorKindToStr to be a bit smarter.
I have tried GetEnumProp method in VCL TypeInfo but it won't work.
So how can I extract the TcxFilterOperatorKind property from a aFilterItem variable to a string and back to a TcxFilterOperatorKind ?
Use the GetEnumName and GetEnumValue duet as Mason pointed out.
And your functions should become much simpler:
function OperatorKindToStr(const aOperatorKind: TcxFilterOperatorKind): string;
begin
Result := GetEnumName(TypeInfo(TcxFilterOperatorKind), Ord(aOperatorKind));
end;
function StrToOperatorKind(const aOpKindStr: string): TcxFilterOperatorKind;
begin
Result := TcxFilterOperatorKind(GetEnumValue(TypeInfo(TcxFilterOperatorKind), aOpKindStr));
end;
GetEnumProp didn't work because it's the wrong function for what you're trying to do. You're close, though. Try GetEnumName and GetEnumValue, which are also in the TypInfo unit.

What is the fastest way to check if two Tbitmaps are the same?

Is there a better way than examine them pixel by pixel?
You can save both Bitmaps to TMemoryStream and compare using CompareMem:
function IsSameBitmap(Bitmap1, Bitmap2: TBitmap): Boolean;
var
Stream1, Stream2: TMemoryStream;
begin
Assert((Bitmap1 <> nil) and (Bitmap2 <> nil), 'Params can''t be nil');
Result:= False;
if (Bitmap1.Height <> Bitmap2.Height) or (Bitmap1.Width <> Bitmap2.Width) then
Exit;
Stream1:= TMemoryStream.Create;
try
Bitmap1.SaveToStream(Stream1);
Stream2:= TMemoryStream.Create;
try
Bitmap2.SaveToStream(Stream2);
if Stream1.Size = Stream2.Size Then
Result:= CompareMem(Stream1.Memory, Stream2.Memory, Stream1.Size);
finally
Stream2.Free;
end;
finally
Stream1.Free;
end;
end;
begin
if IsSameBitmap(MyImage1.Picture.Bitmap, MyImage2.Picture.Bitmap) then
begin
// your code for same bitmap
end;
end;
I did not benchmark this code X scanline, if you do, please let us know which one is the fastest.
Using ScanLine, Without TMemoryStream.
function IsSameBitmapUsingScanLine(Bitmap1, Bitmap2: TBitmap): Boolean;
var
i : Integer;
ScanBytes : Integer;
begin
Result:= (Bitmap1<>nil) and (Bitmap2<>nil);
if not Result then exit;
Result:=(bitmap1.Width=bitmap2.Width) and (bitmap1.Height=bitmap2.Height) and (bitmap1.PixelFormat=bitmap2.PixelFormat) ;
if not Result then exit;
ScanBytes := Abs(Integer(Bitmap1.Scanline[1]) - Integer(Bitmap1.Scanline[0]));
for i:=0 to Bitmap1.Height-1 do
Begin
Result:=CompareMem(Bitmap1.ScanLine[i],Bitmap2.ScanLine[i],ScanBytes);
if not Result then exit;
End;
end;
Bye.
If you need an accurate answer, no. If you need an approximation, you probably could check a selection of pixels. But if you want to find out if the two bitmaps are exactly identical you need to compare the entire pixel and pixel format data.

Getting LastAccessTime with Delphi

I am currently using the following guidelines to get a file's "LastAccessTime" with Delphi
http://www.latiumsoftware.com/en/delphi/00007.php
Using FindNext, have access to a TSearchRec object from which I can access ftLastWriteTime which is of type TFileTime
when converting this to a TDateTime object (using the above source) and then outputting DateTimeToString I get the date and time out but the hour seems to be the sum of the two digits in the files ftLastWriteTime hour value.
i.e instead of getting 2009/09/03 13:45 I get 2009/09/03 04:45 or
instead of 2009/09/03 17:45 I get 2009/09/03 08:45
Any comments are most welcome, thanks in advance
"As usual" ;-) I'll point to the DSiWin32 which includes function DSiGetFileTimes which returns creation time, last access time and last modification time.
function DSiFileTimeToDateTime(fileTime: TFileTime; var dateTime: TDateTime): boolean;
var
sysTime: TSystemTime;
begin
Result := FileTimeToSystemTime(fileTime, sysTime);
if Result then
dateTime := SystemTimeToDateTime(sysTime);
end; { DSiFileTimeToDateTime }
function DSiGetFileTimes(const fileName: string; var creationTime, lastAccessTime,
lastModificationTime: TDateTime): boolean;
var
fileHandle : cardinal;
fsCreationTime : TFileTime;
fsLastAccessTime : TFileTime;
fsLastModificationTime: TFileTime;
begin
Result := false;
fileHandle := CreateFile(PChar(fileName), GENERIC_READ, FILE_SHARE_READ, nil,
OPEN_EXISTING, 0, 0);
if fileHandle <> INVALID_HANDLE_VALUE then try
Result :=
GetFileTime(fileHandle, #fsCreationTime, #fsLastAccessTime,
#fsLastModificationTime) and
DSiFileTimeToDateTime(fsCreationTime, creationTime) and
DSiFileTimeToDateTime(fsLastAccessTime, lastAccessTime) and
DSiFileTimeToDateTime(fsLastModificationTime, lastModificationTime);
finally
CloseHandle(fileHandle);
end;
end; { DSiGetFileTimes }
Typical, 20 minutes after making my first post I solve my own problem.
The author to the linked code avbove had two versions of the same code the second one is posted here http://www.latiumsoftware.com/en/delphi/00051.php
Problem solved! - I reckon the DOS library's interpretation of the Win32 timestamps was incorrect and that carried over into the code that followed. Maybe not? i will investigate futher if time allows.
The timestamps are in UTC, not local time.

Resources