Shirish11
Shirish11

Reputation: 1617

Delphi FileSetDate is erroneous

I want to modify the updated date of a file. So I use the following code to do it.

procedure FileDateUpdate;
var
  date1,date2 : TDateTime;
  file1, file2 : string;
begin
  file1 := 'G:\ab.pdf';
  file2 := 'G:\Shirish\ab.pdf';
  FileAge( file1, date1);
  FileSetDate( file2, DateTimeToFileDate(date1) );
  Fileage( file2, date2);
  ShowMessage('File1 date: '+ DateTimeToStr(date1) + '|| File2 date: '+ DateTimeToStr(date2));
end;

Output

File1 date: 24-05-2016 11:34:35|| File2 date: 24-05-2016 11:34:34

Interestingly the dates are never the same on both the files.

If I use the deprecated method FileAge it works fine

i := FileAge(file1);
FileSetDate(file2, i);
j := FileAge(file2);
ShowMessage('File1 date: '+ DateTimeToStr(FileDateToDateTime(i)) + '|| File2 date: '+ DateTimeToStr(FileDateToDateTime(j)));

Output

File1 date: 24-05-2016 11:34:36|| File2 date: 24-05-2016 11:34:36

Upvotes: 0

Views: 1546

Answers (1)

Peter CrossTheRiver
Peter CrossTheRiver

Reputation: 37

Over time I have collected some functions in some units from www. (I do not remember if I've changed some of them).

Perhaps this could be of help to chance (I used this for change the "Puvananthiran delphi notepad" for updated the file loaded according to the last modification date).`

unit FileTimeUtils;

interface

uses
  SysUtils, Windows;

function DateTimeToFileTime(const aDt: TDateTime): TFileTime;
function FileTimeToDateTime(ft: TFileTime): TDateTime;

procedure DaDateTimeToFileTime(const aDt: TDateTime; var aFileTime: TFileTime);
procedure DaFileTimeToDateTime(ft: TFileTime; var aDateTime: TDateTime);

function FindLastWrittenFile(const aDir, aSearch: String): String;
function GetFileDateTime(const aFileName: String; var aCreationTime, aLastAccessTime, aLastModificationTime: TDateTime): Boolean;
function SetFileDateTime(const aFileName: String; aNewCreationTime, aNewAccessTime, aNewModifyTime: TDateTime): Boolean;

function GetCreationTime(const aFileName: String): TDateTime;
function GetLastAccessTime(const aFileName: String): TDateTime;
function GetLastWriteTime(const aFileName: String): TDateTime;

function SetCreationTime(const aFileName: String; aNewCreationTime: TDateTime): Boolean;
function SetLastAccessTime(const aFileName: String; aNewAccessTime: TDateTime): Boolean;
function SetLastWriteTime(const aFileName: String; aNewModifyTime: TDateTime): Boolean;

implementation


function DateTimeToFileTime(const aDt: TDateTime): TFileTime;
var
  st: TSystemTime;
begin
  DateTimeToSystemTime(aDt, st);
  if not (SystemTimeToFileTime(st, Result) and LocalFileTimeToFileTime(Result, Result)) then
    RaiseLastOSError
end;


function FileTimeToDateTime(ft: TFileTime): TDateTime;
var
  st: TSystemTime;
begin
  if not (FileTimeToLocalFileTime(ft, ft) and FileTimeToSystemTime(ft, st)) then
    RaiseLastOSError;
  Result:= SystemTimeToDateTime(st)
end;


procedure DaDateTimeToFileTime(const aDt: TDateTime; var aFileTime: TFileTime);
begin
  aFileTime:= DateTimeToFileTime(aDt)
end;


procedure DaFileTimeToDateTime(ft: TFileTime; var aDateTime: TDateTime);
begin
  aDateTime:= FileTimeToDateTime(ft)
end;


function FindLastWrittenFile(const aDir, aSearch: String): String;
var
  Dir: String;
  vR:  TSearchRec;
  LastWrite, LastWriteAllFiles: TDateTime;
begin
  {$Warnings Off}
  Dir:= IncludeTrailingBackslash(aDir);
  LastWriteAllFiles:= 0;
  Result:= '';
  if FindFirst(Dir + aSearch, faAnyFile - faDirectory, vR) = 0 then
    repeat
      LastWrite:= FileTimeToDateTime(vR.FindData.ftLastWriteTime);
      {$Warnings On}
      if LastWrite > LastWriteAllFiles then
      begin
        LastWriteAllFiles:= LastWrite;
        Result:= vR.Name
      end
    until FindNext(vR) <> 0;
  SysUtils.FindClose(vR)
end;


function GetFileDateTime(const aFileName: String; var aCreationTime, aLastAccessTime, aLastModificationTime: TDateTime): Boolean;
var
  FileHandle: Cardinal;
  CreationTime, LastAccessTime, LastWriteTime: TFileTime;
begin
  Result:= False;
  FileHandle:= CreateFile(PChar(aFileName), GENERIC_READ, FILE_SHARE_READ, nil, OPEN_EXISTING, 0, 0);
  if FileHandle <> INVALID_HANDLE_VALUE then
    try
      Result:= GetFileTime(FileHandle, @CreationTime, @LastAccessTime, @LastWriteTime);
      DaFileTimeToDateTime(CreationTime, aCreationTime);
      DaFileTimeToDateTime(LastAccessTime, aLastAccessTime);
      DaFileTimeToDateTime(LastWriteTime, aLastModificationTime)
    finally
      CloseHandle(FileHandle)
    end
end; { GetFileDateTime }


function SetFileDateTime(const aFileName: String; aNewCreationTime, aNewAccessTime, aNewModifyTime: TDateTime): Boolean;
var
  FileHandle: Cardinal;
  CreationTime, LastAccessTime, LastWriteTime: TFileTime;
begin
  Result:= False;

  CreationTime := DateTimeToFileTime(aNewCreationTime);
  LastAccessTime:= DateTimeToFileTime(aNewAccessTime);
  LastWriteTime:= DateTimeToFileTime(aNewModifyTime);

  FileHandle:= FileOpen(aFileName, fmOpenReadWrite or fmShareExclusive);
  try
    if SetFileTime(FileHandle, @CreationTime, @LastAccessTime, @LastWriteTime) then
      Result:= True
  finally
    FileClose(FileHandle)
  end
end; { SetFileDateTime }


function GetCreationTime(const aFileName: String): TDateTime;
var
  ffd: TWin32FindData;
  dft: DWord;
  LFT: TFileTime;
  h: THandle;
begin
  Result:= 0;
  h:= Windows.FindFirstFile(PChar(aFileName), ffd);
  if INVALID_HANDLE_VALUE <> h then
  begin
    Windows.FindClose(h);
    FileTimeToLocalFileTime(ffd.ftCreationTime, LFT);
    FileTimeToDosDateTime(LFT, LongRec(dft).Hi, LongRec(dft).Lo);
    Result:= FileDateToDateTime(dft)
  end
end;


{------------------------------------------------------------------------------
  "GetLastAccessTime()" will return a given file's last access time
  as a Delphi "TDateTime" type which you can convert to a string by using the
  "DateTimeToStr()" function. For example:

  MessageDlg('c:config.sys was last accessed on ' +
    DateTimeToStr( GetLastAccessTime( 'c:config.sys' ) ),
    mtInformation, [mbOk], 0 );
------------------------------------------------------------------------------}

function GetLastAccessTime(const aFileName: String): TDateTime;
var
  ffd: TWin32FindData;
  dft: DWord;
  LFT: TFileTime;
  h: THandle;
begin
  Result:= 0;
  // get file information
  h:= Windows.FindFirstFile(PChar(aFileName), ffd);
  if INVALID_HANDLE_VALUE <> h then
  begin

    // we're looking for just one file,
    // so close our "find"
    Windows.FindClose(h);

    // convert the FILETIME to
    // local FILETIME
    FileTimeToLocalFileTime(ffd.ftLastAccessTime, LFT);

    // convert FILETIME to
    // DOS time
    FileTimeToDosDateTime(LFT, LongRec(dft).Hi, LongRec(dft).Lo);

    // finally, convert DOS time to
    // TDateTime for use in Delphi's
    // native date/time functions
    Result:= FileDateToDateTime(dft)
  end
end;


function GetLastWriteTime(const aFileName: String): TDateTime;
var
  ffd: TWin32FindData;
  dft: DWord;
  LFT: TFileTime;
  h: THandle;
begin
  Result:= 0;
  h:= Windows.FindFirstFile(PChar(aFileName), ffd);
  if INVALID_HANDLE_VALUE <> h then
  begin
    Windows.FindClose(h);
    FileTimeToLocalFileTime(ffd.ftLastWriteTime, LFT);
    FileTimeToDosDateTime(LFT, LongRec(dft).Hi, LongRec(dft).Lo);
    Result:= FileDateToDateTime(dft)
  end
end;


function SetCreationTime(const aFileName: String; aNewCreationTime: TDateTime): Boolean;
var
  FileHandle: Cardinal;
  CreationTime, LastAccessTime, LastWriteTime: TDateTime;
  ftCreationTime, ftLastAccessTime, ftLastWriteTime: TFileTime;
begin
  Result:= False;
  if not GetFileDateTime(aFileName, CreationTime, LastAccessTime, LastWriteTime) then
    Exit;

  ftCreationTime := DateTimeToFileTime(aNewCreationTime);
  ftLastAccessTime:= DateTimeToFileTime(LastAccessTime);
  ftLastWriteTime:= DateTimeToFileTime(LastWriteTime);

  FileHandle:= FileOpen(aFileName, fmOpenReadWrite or fmShareExclusive);
  try
    if SetFileTime(FileHandle, @ftCreationTime, @ftLastAccessTime, @ftLastWriteTime) then
      Result:= True
  finally
    FileClose(FileHandle)
  end
end; { SetCreationTime }


function SetLastAccessTime(const aFileName: String; aNewAccessTime: TDateTime): Boolean;
var
  FileHandle: Cardinal;
  CreationTime, LastAccessTime, LastWriteTime: TDateTime;
  ftCreationTime, ftLastAccessTime, ftLastWriteTime: TFileTime;
begin
  Result:= False;
  if not GetFileDateTime(aFileName, CreationTime, LastAccessTime, LastWriteTime) then
    Exit;

  ftCreationTime := DateTimeToFileTime(CreationTime);
  ftLastAccessTime:= DateTimeToFileTime(aNewAccessTime);
  ftLastWriteTime:= DateTimeToFileTime(LastWriteTime);

  FileHandle:= FileOpen(aFileName, fmOpenReadWrite or fmShareExclusive);
  try
    if SetFileTime(FileHandle, @ftCreationTime, @ftLastAccessTime, @ftLastWriteTime) then
      Result:= True
  finally
    FileClose(FileHandle)
  end
end; { SetLastAccessTime }


function SetLastWriteTime(const aFileName: String; aNewModifyTime: TDateTime): Boolean;
var
  FileHandle: Cardinal;
  CreationTime, LastAccessTime, LastWriteTime: TDateTime;
  ftCreationTime, ftLastAccessTime, ftLastWriteTime: TFileTime;
begin
  Result:= False;
  if not GetFileDateTime(aFileName, CreationTime, LastAccessTime, LastWriteTime) then
    Exit;

  ftCreationTime := DateTimeToFileTime(CreationTime);
  ftLastAccessTime:= DateTimeToFileTime(LastAccessTime);
  ftLastWriteTime:= DateTimeToFileTime(aNewModifyTime);

  FileHandle:= FileOpen(aFileName, fmOpenReadWrite or fmShareExclusive);
  try
    if SetFileTime(FileHandle, @ftCreationTime, @ftLastAccessTime, @ftLastWriteTime) then
      Result:= True
  finally
    FileClose(FileHandle)
  end
end; { SetLastWriteTime }

end.

the usage is simple:

// For Test: Drag two files in executable program self

program FileDateUpdate;

{$APPTYPE CONSOLE}

uses
  Windows, FileTimeUtils;

{$R *.res}

var
  FirstFile, UpdateFile, msg1, msg2: String;
  CreationTime, LastWriteTime, LastAccessTime: TDateTime;

begin
  FirstFile := ParamStr(1);
  UpdateFile:= ParamStr(2);

  msg1:= 'First file is  ' + FirstFile + '   -   Second file is  ' + UpdateFile;

  msg1:= msg1 + #13#10 + #13#10 + 'Note: The second file get the date of first file...';

  msg2:= ' Confirm ?';

  if MessageBox(0, Pchar(msg1), Pchar(msg2), MB_YESNO + MB_ICONQUESTION) = IDYES  then
  begin
    GetFileDateTime(FirstFile, CreationTime, LastAccessTime, LastWriteTime);
    SetFileDateTime(UpdateFile, CreationTime, LastAccessTime, LastWriteTime)
  end
end.
`

Upvotes: 1

Related Questions