2009-09-19 7 views
0

Je cache des fichiers localement dans mon application à 3 niveaux. Pour vérifier si lire le fichier du cache local ou du serveur je compare des dates de dossier. J'ai trouvé que lors de la conversion des dates de fichier en TDateTime et viceversa il y a des incohérences et des valeurs qui devraient correspondre rarement. Voici un code qui illustre le problèmeComment corriger les incohérences lors de la conversion de dates de fichier vers/depuis 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; 

Je suis sûr que cela est dû à un problème d'arrondi. Est-ce que quelqu'un sait un moyen de le réparer?

+0

N'utilisez pas 'TDateTime', utilisez' FILETIME' à la place. Il existe même une fonction 'CompareFileTime()' dans l'API Windows. – mghie

Répondre

4

Vous avez raison au sujet de l'arrondissement. Un TDateTime est en fait un float et comme tous les flottants, vous avez des problèmes d'arrondi. Surtout comparer pour l'égalité est un problème. Des fonctions comme CompareDateTime peuvent aider. De plus, certains systèmes de fichiers n'ont pas la même précision qu'un TDateTime. Certains systèmes de fichiers ont seulement une précision de 2 secondes. Vous devrez peut-être décider d'utiliser moins de précision pour la comparaison en utilisant la fonction SecondsBetween par exemple.

+0

On supposerait que le serveur utilise NTFS, qui a la même résolution que «FILETIME», c'est-à-dire 100 nanosecondes. Quoi qu'il en soit, comparer les horodatages récupérés directement devrait éliminer le besoin d'arrondir ou d'introduire un epsilon, tant qu'il n'y a pas de conversion de type de données. 'TDateTime' est simplement un mauvais type de données à utiliser. – mghie

+0

FAT arrondit aux nombres pairs: http://support.microsoft.com/kb/127830. J'aime votre suggestion d'utiliser CompareFileTime, mais je voudrais quand même tester si cela fonctionne comme prévu pour FAT. –

1

Comparez yout TDateTime en utilisant la fonction 'SameValue' dans l'unité Math. Ceci effectue une comparaison "floue" renvoyant l'égalité si les deux valeurs sont très proches l'une de l'autre (dans un delta par défaut que vous pouvez modifier si vous le souhaitez). Votre règle devrait être: NE JAMAIS JAMAIS effectuer

If FloatA = FloatB then 
    .... 

Il est autorisé à faire:

If FloatA = 0.0 then 
    .... 

mais c'est tout.

Brian.

+0

Merci Brian, je vais essayer votre suggestion. – norgepaul

0

Ce n'est pas une bonne idée de mettre à jour les fichiers en utilisant le datetime système, si vous avez des PC dans différents fuseaux horaires, vous aurez besoin de le monter. utilisez à la place une fonction de hachage pour savoir quand le fichier est différent et qu'une mise à jour est nécessaire.

Le hachage de fichiers est facile, jetez un oeil à http://delphi.about.com/od/objectpascalide/a/delphi-md5-hash.htm par exemple.

Quoi qu'il en soit, getFileTime a une résolution inférieure à celle de tdatetime (plus grande dans les anciens systèmes), mais seulement pour les secondes, alors vous devez faire un tour dans votre comparaison. De MSDN «Tous les systèmes de fichiers ne peuvent pas enregistrer les derniers temps de création et d'accès et tous les systèmes de fichiers ne les enregistrent pas de la même manière: par exemple, sur FAT, le temps de création a une résolution de 10 millisecondes; Par conséquent, la fonction GetFileTime peut ne pas renvoyer le même ensemble d'informations de temps de fichier à l'aide de SetFileTime NTFS retarde les mises à jour du dernier temps d'accès pour un fichier de 2 secondes, et le temps d'accès a une résolution de 1 jour. jusqu'à une heure après le dernier accès. "

+0

Même si je suis d'accord sur le fait que datetime local est une mauvaise base de comparaison, le datetime système (UTC) est certainement un bon. Consultez la documentation de 'GetLocalTime()' et 'GetSystemTime()' pour plus de détails. Votre réponse mélange les deux, vous devriez clarifier cela. Et on utiliserait 'FILETIME' pour les comparaisons, qui a une résolution de 100 nanosecondes. – mghie

+0

Vous avez raison, merci –