Мне нужно сохранить время последней записи файла в Windows в виде строки. Необходимо избегать перехода на летнее время или пользователей в других часовых поясах. Я думаю У меня есть решение, но кажется, что есть много проблем с датами.
У меня нет необходимости сравнивать дату с ранее сохраненной датой. Нужно только знать, изменилось ли оно.
Сохранение необработанной записи TFileTime (представленной как Int64) показалось наилучшим, поскольку именно это фактически используется Windows как 2 DWORDS. Delphi, кажется, хочет использовать TDateTime (FileAge) или целое число (FileSetDate). Кажется, что оба они переводят в местное время и используют только 32 бита против 64 бит.
Мне нужно отобразить «дружественную пользователю» строку, и я сделал строку отображения UTC, чтобы дважды проверить сохраненные значения. Для этого я использовал TDateTime для перевода из формата TFileTime.
Вспомогательный блок выглядит так:
unit FileTimeHelperUnt;
interface
uses
Winapi.Windows, System.SysUtils;
type
TFileTimeHelper = record helper for TFileTime
function ToString: String; //Use to export TFileTime as Int64 String.
function FromString( AString: String ): Boolean; //Use to restore
TFileTime from Int64 String
function GetLastWriteTime( AFilePathStr: String ): Boolean;
function SetLastWriteTime( AFilePathStr: String ): Boolean;
function UTCString: String;
function UserFriendlyString: String; //Like Windows Explorer and Local.
end;
implementation
{ TFileTimeHelper }
function TFileTimeHelper.ToString: String;
var
TmpInt64: Int64 absolute Self;
begin
Result := TmpInt64.ToString;
end;
function TFileTimeHelper.FromString(AString: String): Boolean;
begin
Result := False;
try
Int64(Self) := StrToInt64( AString );
Result := True;
except on E: Exception do
end;
end;
function TFileTimeHelper.GetLastWriteTime(AFilePathStr: String): Boolean;
var
TmpSearchRec: TSearchRec;
begin
Result := False;
if FileExists( AFilePathStr )=False then
Exit;
if FindFirst( AFilePathStr, faAnyFile, TmpSearchRec )=0 then
begin
Self := TmpSearchRec.FindData.ftLastWriteTime;
Result := True;
end;
end;
function TFileTimeHelper.SetLastWriteTime(AFilePathStr: String): Boolean;
var
TmpHandle: THandle;
begin
Result := False;
if FileExists( AFilePathStr )=False then
Exit;
try
TmpHandle := FileOpen(AFilePathStr, fmOpenWrite);
if TmpHandle = THandle(-1) then
Exit;
try
SetFileTime(TmpHandle, nil, nil, @Self);
Result := (GetLastError=0);
finally
FileClose( TmpHandle );
end;
except on E: Exception do
end;
end;
function TFileTimeHelper.UTCString: String;
var
TmpSystemTime: TSystemTime;
TmpDateTime: TDateTime;
begin
FileTimeToSystemTime( Self, TmpSystemTime );
TmpDateTime := SystemTimeToDateTime(TmpSystemTime);
Result := DateTimeToStr( TmpDateTime );
end;
function TFileTimeHelper.UserFriendlyString: String;
var
TmpSystemTime: TSystemTime;
TmpLocalLastWriteFileTime: TFileTime;
TmpDateTime: TDateTime;
begin
FileTimeToLocalFileTime( Self, TmpLocalLastWriteFileTime );
FileTimeToSystemTime( TmpLocalLastWriteFileTime, TmpSystemTime );
TmpDateTime := SystemTimeToDateTime(TmpSystemTime);
Result := FormatDateTime( 'm/d/yyyy h:nn ampm', TmpDateTime );
end;
end.
Вызывающее устройство выглядит так:
procedure TForm12.btnGetFileDate2Click(Sender: TObject);
var
TmpFileTime: TFileTime;
begin
TmpFileTime.GetLastWriteTime( 'File.txt' );
edtFileDateTime.Text := TmpFileTime.ToString;
edtLocalFileDateTime.Text := TmpFileTime.UserFriendlyString;
edtUTCDateTime.Text := TmpFileTime.UTCString;
end;
procedure TForm12.btnSetFileDate2Click(Sender: TObject);
var
TmpFileTime: TFileTime;
begin
TmpFileTime.FromString( edtFileDateTime.Text );
TmpFileTime.SetLastWriteTime( 'File.txt' );
end;
Кажется, все работает хорошо. На данный момент меня не беспокоит изменение TFileTime с 64-битного. Надеюсь, я не пропустил ни одного сценария, который может вызвать проблемы.
Кроме того, мы надеемся, что кто-то еще может найти это полезным, если проблем не много.
Вопрос в том, будет ли этот код работать в любом часовом поясе или при переходе на летнее время? Я думаю, что этот код должен избегать проблемы "сохранить сейчас и загрузить после изменения летнего времени". Или проблема «Сохранить в моем часовом поясе, а затем загрузить другим пользователем в другом часовом поясе». Структура TFileTime должна остаться прежней, и моя программа обнаружит, что она не изменилась. Не уверен, что у меня есть все потенциальные проблемы в списке. В принципе, есть ли случай, когда сохранение строки и загрузка позже или в другом месте заставит мою программу подумать об изменении?
Спасибо.