Как исправить несоответствия при преобразовании дат файлов в / из TDateTime - PullRequest
0 голосов
/ 19 сентября 2009

Я кеширую файлы локально в моем 3-х уровневом приложении. Чтобы проверить, читать ли файл из локального кэша или с сервера, я сравниваю даты файлов. Я обнаружил, что при преобразовании дат файлов в TDateTime и наоборот возникают несоответствия и значения, которые должны соответствовать редко. Вот код, который решает проблему

procedure TestFileDateConversion;
const
  Dir = 'c:\TestDir\';
  Filename = 'test.txt';
var
  FileDate, NewFileDate: TDateTime;
  FilePath: String;
  FileHandle: THandle;
begin
  ForceDirectories(Dir);

  FilePath := concat(Dir, Filename);

  // Create the file if it doesn't already exist
  FileCreate(FilePath);

  FileDate := now;

  // Set the file date
  try
    FileHandle := FileOpen(FileName, fmOpenWrite OR fmShareDenyNone);

    if FileHandle > 0 Then
      FileSetDate(FileHandle, DateTimeToFileDate(FileDate));
  finally
    FileClose(FileHandle);
  end;

  // Check that the expected file date and the actual file date match
  if (FileAge(FilePath, NewFileDate)) and (FileDate <> NewFileDate) then
    ShowMessage('File dates do not match'); // More often than not, they don't
end;

Я уверен, что это вызвано некоторой проблемой округления. Кто-нибудь знает способ это исправить?

Ответы [ 3 ]

4 голосов
/ 19 сентября 2009

Вы правы насчет округления. TDateTime на самом деле является плавающей точкой, и, как и все плавающие точки, у вас есть проблемы с округлением. Особенно сравнение на равенство является проблемой. Такие функции, как CompareDateTime, могут помочь. Также некоторые файловые системы не имеют такую ​​же точность, как TDateTime. Некоторые файловые системы имеют точность только 2 секунды. Поэтому вам может потребоваться использовать меньшую точность для сравнения, например, с помощью функции SecondsBetween.

1 голос
/ 19 сентября 2009

Сравните ваши TDateTime с использованием функции SameValue в модуле Math. При этом выполняется «нечеткое» сравнение, возвращающее равенство, если два значения очень близки друг к другу (в дельте по умолчанию, которую вы можете изменить, если хотите) Ваше правило должно быть: НИКОГДА не выполнять

If FloatA = FloatB then
   ....

Это нормально делать:

If FloatA = 0.0 then
  ....

но это все.

Брайан.

0 голосов
/ 20 сентября 2009

Не рекомендуется обновлять файлы, используя системную дату и время, если у вас есть шт в разных часовых поясах, вам нужно будет ездить на них. вместо этого используйте хеш-функцию, чтобы узнать, когда файл отличается и требуется обновление.

Хэширование файлов легко, посмотрите, например, http://delphi.about.com/od/objectpascalide/a/delphi-md5-hash.htm.

В любом случае, getFileTime имеет более низкое разрешение, чем tdatetime (больше в старых системах), но только на несколько секунд, тогда вам нужно сделать обход в сравнении.

Из MSDN "Не все файловые системы могут записывать время создания и последнего доступа, и не все файловые системы записывают их одинаково. Например, в FAT время создания имеет разрешение 10 миллисекунд, время записи имеет разрешение 2 секунды, а время доступа имеет разрешение 1 день (на самом деле, дату доступа). Поэтому функция GetFileTime может не возвращать ту же информацию о времени файла, установленную с помощью SetFileTime. NTFS задерживает обновление времени последнего доступа к файлу до через час после последнего доступа. "

...