Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

File time comparison error

2 views
Skip to first unread message

mp

unread,
Dec 30, 2009, 8:40:10 AM12/30/09
to
I seem to be getting a result i'm not expecting
using api to get file time of two 'identical' files on different drives
working on a file backup app to synchronize my portable hard drive and
laptop

on one file that i know for sure is same date on both drives (as seen in
explorer)
i get the following times
Time for file 1: 3005030930305536
Time for file 2: 3005030913683296
lngCompare <1>

as you can see the filetimes are different, but in explorer they are the
same
what am i doing wrong?

in my compareSaveTime sub
'get file times(function below)
retFileTimeA = GetFileSavedTimeObj(msFullName)
retFileTimeB = GetFileSavedTimeObj(sFileNameB)

If msFullName = "Z:\0\Support\MCS\LISP\StartUp\MCS.MNL" Then
LogEntry "Time for file 1: " & CStr(retFileTimeA.dwHighDateTime) &
CStr(retFileTimeA.dwLowDateTime)
LogEntry "Time for file 2: " & CStr(retFileTimeB.dwHighDateTime) &
CStr(retFileTimeB.dwLowDateTime)
End If


Dim lngCompare As Integer
'using api function to comparetimes
'Private Declare Function CompareFileTime Lib "kernel32" (lpFileTime1 As
FILETIME, lpFileTime2 As FILETIME) As Long
lngCompare = CompareFileTime(retFileTimeA, retFileTimeB)
'just put this in for debug...this is the one with wrong report...probably
all are...
If msFullName = "Z:\0\Support\MCS\LISP\StartUp\MCS.MNL" Then
LogEntry "lngCompare ", lngCompare
End If

'the getFileTime function
Private Function GetFileSavedTimeObj(ByVal sFileName As String) As FILETIME
Dim lngFhndl As Long
Dim ftCreated As FILETIME
Dim ftLastAccess As FILETIME
Dim ftSaved As FILETIME
'local time
Dim ftlocSaved As FILETIME
'system time
Dim ftsysSaved As SYSTEMTIME
lngFhndl = FileHandle(sFileName)

'fill in filetime structures
'If the function succeeds, the return value is nonzero.
'If the function fails, the return value is zero.
Dim lrtn As Long
lrtn = GetFileTime(lngFhndl, ftCreated, ftLastAccess, ftSaved)
CloseFile (lngFhndl)
If lrtn = 0 Then
' Debug.Print "GetFileTime Failed on " & sFileName
Else

'Convert the file time to the local file time
FileTimeToLocalFileTime ftSaved, ftlocSaved

GetFileSavedTimeObj = ftlocSaved
End If

End Function

any hints appreciated
mark


Jim Mack

unread,
Dec 30, 2009, 8:58:39 AM12/30/09
to
mp wrote:
> I seem to be getting a result i'm not expecting
> using api to get file time of two 'identical' files on different
> drives working on a file backup app to synchronize my portable hard
> drive and laptop
>
> on one file that i know for sure is same date on both drives (as
> seen in explorer)
> i get the following times
> Time for file 1: 3005030930305536
> Time for file 2: 3005030913683296
> lngCompare <1>
>
> as you can see the filetimes are different, but in explorer they
> are the same
> what am i doing wrong?

If the files are on different file systems (NTFS vs FAT, e.g.) then
you can't make a guaranteed comparison of file times. The usual rule
is that if file times are within two seconds, they're the same
(because FAT file systems only store the time to the closest even
number of seconds).

You could add logic to detect the file system and enforce exactness
when they're the same, and allow a 2-second window otherwise.

--
Jim Mack
Twisted tees at http://www.cafepress.com/2050inc
"We sew confusion"

mp

unread,
Dec 30, 2009, 3:04:41 PM12/30/09
to
AHA!!!

"Jim Mack" <jm...@mdxi.nospam.com> wrote in message
news:ed9MugVi...@TK2MSFTNGP05.phx.gbl...


> mp wrote:
>> I seem to be getting a result i'm not expecting
>> using api to get file time of two 'identical' files on different
>> drives working on a file backup app to synchronize my portable hard
>> drive and laptop

snip


>
> If the files are on different file systems (NTFS vs FAT, e.g.) then
> you can't make a guaranteed comparison of file times. The usual rule
> is that if file times are within two seconds, they're the same
> (because FAT file systems only store the time to the closest even
> number of seconds).
>
> You could add logic to detect the file system and enforce exactness
> when they're the same, and allow a 2-second window otherwise.
>
> --
> Jim Mack
> Twisted tees at http://www.cafepress.com/2050inc
> "We sew confusion"


Thanks much! hit the nail on the head...
to expose my ignorance (not hard) how would i add 2 seconds to the api call
lngCompare = CompareFileTime(retFileTimeA, retFileTimeB) just returns an
integer
i'm guessing i can interpret FileTimeA.dwHighDateTime or
FileTimeA.dwLowDateTime
in some way to compute seconds?

mark


Bob Butler

unread,
Dec 30, 2009, 3:11:06 PM12/30/09
to

"mp" <nos...@Thanks.com> wrote in message
news:uVBiTtYi...@TK2MSFTNGP05.phx.gbl...
<cut>

> i'm guessing i can interpret FileTimeA.dwHighDateTime or
> FileTimeA.dwLowDateTime
> in some way to compute seconds?

take a look at FileTimeToSystemTime
http://msdn.microsoft.com/en-us/library/ms724280(VS.85).aspx

and perhaps FileTimeToLocalFileTime
http://msdn.microsoft.com/en-us/library/ms724277(VS.85).aspx

mp

unread,
Dec 30, 2009, 7:04:07 PM12/30/09
to

"Bob Butler" <no...@nospam.ever> wrote in message
news:ektioxYi...@TK2MSFTNGP02.phx.gbl...

Thanks for the links,
the closest thing i can find around there is
dwRet = StringCchPrintf(lpszString, dwSize,
TEXT("%02d/%02d/%d %02d:%02d"),
stLocal.wMonth, stLocal.wDay, stLocal.wYear,
stLocal.wHour, stLocal.wMinute);
i can probably convert that to vb, but will have to check if there is a
Seconds member on that struct...
will search that shortly when i get time ... no pun intended ... :-)
Thanks
mark


Bob Butler

unread,
Dec 30, 2009, 7:18:01 PM12/30/09
to

"mp" <nos...@Thanks.com> wrote in message
news:eZRJHzai...@TK2MSFTNGP06.phx.gbl...

>
> "Bob Butler" <no...@nospam.ever> wrote in message
> news:ektioxYi...@TK2MSFTNGP02.phx.gbl...
>>
>> "mp" <nos...@Thanks.com> wrote in message
>> news:uVBiTtYi...@TK2MSFTNGP05.phx.gbl...
>> <cut>
>>> i'm guessing i can interpret FileTimeA.dwHighDateTime or
>>> FileTimeA.dwLowDateTime
>>> in some way to compute seconds?
>>
>> take a look at FileTimeToSystemTime
>> http://msdn.microsoft.com/en-us/library/ms724280(VS.85).aspx
>>
>> and perhaps FileTimeToLocalFileTime
>> http://msdn.microsoft.com/en-us/library/ms724277(VS.85).aspx
>>
>
> Thanks for the links,
> the closest thing i can find around there is
<cut VB.Net crud>

Yeah, you've got to ignore the VB.Net examples they've started adding
everywhere.

> i can probably convert that to vb, but will have to check if there is a
> Seconds member on that struct...

"Type", and there is

> will search that shortly when i get time ... no pun intended ... :-)

something like this should get you started

Private Type SYSTEMTIME
wYear As Integer
wMonth As Integer
wDayOfWeek As Integer
wDay As Integer
wHour As Integer
wMinute As Integer
wSecond As Integer
wMilliseconds As Integer
End Type
Private Type FILETIME
dwLowDateTime As Long
dwHighDateTime As Long
End Type
Private Declare Function SystemTimeToFileTime Lib "kernel32" _
(ByRef lpSystemTime As SYSTEMTIME, ByRef lpFileTime As FILETIME) As Long
Private Declare Function FileTimeToSystemTime Lib "kernel32" _
(ByRef lpFileTime As FILETIME, ByRef lpSystemTime As SYSTEMTIME) As Long
Private Declare Function FileTimeToLocalFileTime Lib "kernel32" _
(ByRef lpFileTime As FILETIME, ByRef lpLocalFileTime As FILETIME) As Long

Public Function LocalSystemTime(ByRef FileTimeInfo As FILETIME) As Date
Dim uLFT As FILETIME
Dim uST As SYSTEMTIME
Dim r As Long
r = FileTimeToLocalFileTime(FileTimeInfo, uft)
r = FileTimeToSystemTime(uFT, uST)
LocalSystemTime = DateSerial(uST.wYear, uST.wMonth, uST.wDay) + _
TimeSerial(uST.wHour, uST.wMinute, uST.wSecond)
End Function


Jim Mack

unread,
Dec 30, 2009, 9:16:26 PM12/30/09
to
> "Jim Mack" wrote...

>> mp wrote:
>>
>> If the files are on different file systems (NTFS vs FAT, e.g.) then
>> you can't make a guaranteed comparison of file times. The usual
>> rule is that if file times are within two seconds, they're the same
>> (because FAT file systems only store the time to the closest even
>> number of seconds).
>>
>
> Thanks much! hit the nail on the head...
> to expose my ignorance (not hard) how would i add 2 seconds to the
> api call lngCompare = CompareFileTime(retFileTimeA, retFileTimeB)
> just returns an integer
> i'm guessing i can interpret FileTimeA.dwHighDateTime or
> FileTimeA.dwLowDateTime
> in some way to compute seconds?

Without actually trying it... here's how I'd approach it.

A system filetime is given in ticks of 100ns. Two seconds represents
2x10^7 ticks. So if two times differ by less than that, they can be
considered identical.

So first compare highparts -- if they're different then that tells the
whole story. If they're identical, subtract the lowparts and compare
the magnitude to the value representing 2 seconds. If it's less,
they're the same. If not, the sign tells you which is older.

mp

unread,
Dec 31, 2009, 8:13:13 AM12/31/09
to

"Jim Mack" <jm...@mdxi.nospam.com> wrote in message

news:eQWB$8biKH...@TK2MSFTNGP02.phx.gbl...


>> "Jim Mack" wrote...
>>> mp wrote:
>>>
>>> If the files are on different file systems (NTFS vs FAT, e.g.) then
>>> you can't make a guaranteed comparison of file times. The usual
>>> rule is that if file times are within two seconds, they're the same
>>> (because FAT file systems only store the time to the closest even
>>> number of seconds).
>>>
>>
>> Thanks much! hit the nail on the head...

snip


>> in some way to compute seconds?
>
> Without actually trying it... here's how I'd approach it.
>
> A system filetime is given in ticks of 100ns. Two seconds represents
> 2x10^7 ticks. So if two times differ by less than that, they can be
> considered identical.
>
> So first compare highparts -- if they're different then that tells the
> whole story. If they're identical, subtract the lowparts and compare
> the magnitude to the value representing 2 seconds. If it's less,
> they're the same. If not, the sign tells you which is older.
>
> --
> Jim Mack
> Twisted tees at http://www.cafepress.com/2050inc
> "We sew confusion"
>

Thanks much...I'll try that in a while
meanwhile last night....
after converting filetime to systemtime and comparing the struct parts I get
a variation in the DAY part!
file1
788441 year
1835009 month
42 day
0 hour
0 minute

file2
788441 year
1835009 month
22085672 day
0 hour
0 minute

I'll look at the latest suggestions,
thanks Jim and Bob
mark


Bob Butler

unread,
Dec 31, 2009, 8:36:02 AM12/31/09
to

"mp" <nos...@Thanks.com> wrote in message
news:OMxvCshi...@TK2MSFTNGP06.phx.gbl...
<cut>

> meanwhile last night....
> after converting filetime to systemtime and comparing the struct parts I
> get a variation in the DAY part!
> file1
> 788441 year
> 1835009 month
> 42 day

Year, Month, Day, etc should all look like real year,month, and day values
so something isn't right. Either your initial filetime value is bad or you
aren't doing the conversions correctly. Maybe by year 788441 they'll have
1835009 42-day months each year but I doubt the info makes much sense
today...

Nobody

unread,
Dec 31, 2009, 11:56:09 AM12/31/09
to
"mp" <nos...@Thanks.com> wrote in message
news:OMxvCshi...@TK2MSFTNGP06.phx.gbl...
> file1
> 788441 year
> 1835009 month
> 42 day
> 0 hour
> 0 minute
>
> file2
> 788441 year
> 1835009 month
> 22085672 day
> 0 hour
> 0 minute
>
> I'll look at the latest suggestions,
> thanks Jim and Bob

Year value and its Hex representation:

788441 = 000C 07D9 (Hex)

000C (Hex) = 12 Decimal
07D9 (Hex) = 2009 Decimal

Obviously you are using Long instead of Integer when declaring SYSTEMTIME.
All members should be Integer.


mp

unread,
Dec 31, 2009, 4:01:15 PM12/31/09
to

"Nobody" <nob...@nobody.com> wrote in message
news:u9Gb4oji...@TK2MSFTNGP05.phx.gbl...

Sure nuff'
don't remember where i got these defs long ago

Private Declare Function GetFileTime Lib "kernel32" (ByVal hFile As Long,
lpCreationTime As FILETIME, lpLastAccessTime As FILETIME, lpLastWriteTime As
FILETIME) As Long
Private Declare Function FileTimeToSystemTime Lib "kernel32" (lpFileTime As
FILETIME, lpSystemTime As SYSTEMTIME) As Long
Private Declare Function FileTimeToLocalFileTime Lib "kernel32" (lpFileTime
As FILETIME, lpLocalFileTime As FILETIME) As Long


Private Declare Function CompareFileTime Lib "kernel32" (lpFileTime1 As
FILETIME, lpFileTime2 As FILETIME) As Long

Private Type SYSTEMTIME
wYear As Long
wMonth As Long
wDayOfWeek As Long
wDay As Long
wHour As Long
wMinute As Long
wSecond As Long
wMilliseconds As Long
End Type

so I'll change system time type def
should the function defs also be integer instead of long?

thanks
mark


mp

unread,
Jan 1, 2010, 12:22:56 PM1/1/10
to

"Jim Mack" <jm...@mdxi.nospam.com> wrote in message

news:eQWB$8biKH...@TK2MSFTNGP02.phx.gbl...

not sure i've got this right...
'thanks to JimMack for this function concept
Private Function CompareFileTimes(FileTimeA As FILETIME, FileTimeb As
FILETIME, lSecondsFuzz As Long) As Long
'0 - both files same
'1 - first file newer
'2 - second file newer

'A system filetime is given in ticks of 100ns. Two seconds represents


'2x10^7 ticks. So if two times differ by less than that, they can be
'considered identical.
'
'So first compare highparts -- if they're different then that tells the
'whole story.

If FileTimeA.dwHighDateTime <> FileTimeb.dwHighDateTime Then
If FileTimeA.dwHighDateTime < FileTimeb.dwHighDateTime Then
CompareFileTimes = 2
Else
CompareFileTimes = 1
End If
Exit Function

Else
'If they're identical, subtract the lowparts and compare


'the magnitude to the value representing 2 seconds. If it's less,
'they 're the same. If not, the sign tells you which is older.

'
Dim lticks As Long
lticks = lSecondsFuzz * 10 ^ 7

If Abs(FileTimeA.dwLowDateTime - FileTimeb.dwLowDateTime) > lticks Then
If FileTimeA.dwLowDateTime < FileTimeb.dwLowDateTime Then
CompareFileTimes = 2
Else
CompareFileTimes = 1
End If
Exit Function
Else
CompareFileTimes = 0
End If
End If

End Function


mp

unread,
Jan 1, 2010, 12:29:33 PM1/1/10
to
think i fixed it...maybe
lticks = lSecondsFuzz * (10 ^ 7)

i'm sure it's terrible code, but is it correct functionally?

"mp" <nos...@Thanks.com> wrote in message

news:ut8pPcwi...@TK2MSFTNGP04.phx.gbl...

Jim Mack

unread,
Jan 1, 2010, 1:25:53 PM1/1/10
to
mp wrote:
> think i fixed it...maybe
> lticks = lSecondsFuzz * (10 ^ 7)
>
> i'm sure it's terrible code, but is it correct functionally?

It looks like it reproduces what I wrote, but it's hard to follow
because of the indenting.

To simplify it for ease of reading:

Dim Delta As Long, Diff As Long

Delta = 2 * (10^7)

If A.Hi > B.Hi Then
Result = 1
ElseIf B.Hi > A.Hi Then
Result = 2
Else
Result = 0
Diff = A.Lo - B.Lo
If Abs(Diff) > Delta Then
Select Case Sgn(Diff)
Case -1 (A - B) < 0, so B > A
Result = 2
Case 1
Result = 1
End Select
End If
End If

I think I kept your convention -- if A > B then Result = 1; if B > A
then Result = 2. Right?

BTW, I believe the high parts of FILETIMEs are equal only if the
complete times are within 7 minutes of each other, so that relatively
costly Else clause will not often be executed.

That's the theory, anyway. Still untested.

--
Jim Mack
Twisted tees at http://www.cafepress.com/2050inc
"We sew confusion"

>

Larry Serflaten

unread,
Jan 1, 2010, 3:04:56 PM1/1/10
to

"Jim Mack" <jm...@mdxi.nospam.com> wrote

> To simplify it for ease of reading:

Another simplification... (also not tested)

LFS


Function FileTimeComp(ByVal FileTimeA As FILETIME, ByVal FileTimeB As FILETIME, Optional ResolutionInSeconds As Long = 2) As
Long
Const Nano As Long = 10 ^ 7 ' 1 second using 100 nanosecond units
' CAUTION: ResolutionInSeconds causes OVERFLOW ERROR at 215+
' Return values: (Similar to StrComp)
' A < B = -1
' A = B = 0
' A > B = 1

FileTimeComp = Sgn(FileTimeA.dwHighDateTime - FileTimeB.dwHighDateTime)
If FileTimeComp = 0 Then
FileTimeA.dwLowDateTime = FileTimeA.dwLowDateTime \ (Nano * ResolutionInSeconds)
FileTimeB.dwLowDateTime = FileTimeB.dwLowDateTime \ (Nano * ResolutionInSeconds)
FileTimeComp = Sgn(FileTimeA.dwLowDateTime - FileTimeB.dwLowDateTime)
End If
End Function

mp

unread,
Jan 1, 2010, 4:54:03 PM1/1/10
to

"Jim Mack" <jm...@mdxi.nospam.com> wrote in message
news:uUlBX$wiKHA...@TK2MSFTNGP04.phx.gbl...

> mp wrote:
>> think i fixed it...maybe
>> lticks = lSecondsFuzz * (10 ^ 7)
>>
>> i'm sure it's terrible code, but is it correct functionally?
>
> It looks like it reproduces what I wrote, but it's hard to follow
> because of the indenting.

is that too much indenting or too little?

> To simplify it for ease of reading:

snip

thanks

> I think I kept your convention -- if A > B then Result = 1; if B > A
> then Result = 2. Right?

right

the only reason i'm deviating from the standard -1,0,1 is i'm using
-3 = both files missing
-2 = second file missing
-1 = first file missing
0 = both files same
1 = first file newer
2 = second file newer

> BTW, I believe the high parts of FILETIMEs are equal only if the
> complete times are within 7 minutes of each other, so that relatively
> costly Else clause will not often be executed.
>
> That's the theory, anyway. Still untested.
>
> --
> Jim Mack

thanks
mark


mp

unread,
Jan 1, 2010, 4:55:22 PM1/1/10
to
Thanks Larry,
very clean
mark

"Larry Serflaten" <serf...@usinternet.com> wrote in message
news:%23jgZf2x...@TK2MSFTNGP05.phx.gbl...

Jim Mack

unread,
Jan 1, 2010, 5:29:03 PM1/1/10
to
Larry Serflaten wrote:
> "Jim Mack" <jm...@mdxi.nospam.com> wrote
>
>> To simplify it for ease of reading:
>
> Another simplification... (also not tested)


Sure, change the convention to make it easier (-:

You might want to also handle the case where the caller wants an exact
match (ResInSec = 0)

--
Jim

Jim Mack

unread,
Jan 1, 2010, 5:32:26 PM1/1/10
to
mp wrote:
>
> is that too much indenting or too little?

Just a combination of wrapping and one-space indents. A min of two
spaces is better IMO.

When posting code it can help to indent the whole block a couple of
spaces. That way if a line wraps it's obvious, because it will start
in the undented zone.

Larry Serflaten

unread,
Jan 1, 2010, 5:55:18 PM1/1/10
to

"Jim Mack" <jm...@mdxi.nospam.com> wrote

> You might want to also handle the case where the caller wants an exact
> match (ResInSec = 0)

Doh!

That and error handling, plus the special &HFFFFFFFF condition,
(times less than zero...)

Perhaps it was a bit of over-simplification.

:-)
LFS

mp

unread,
Jan 2, 2010, 8:58:35 AM1/2/10
to

"Jim Mack" <jm...@mdxi.nospam.com> wrote in message
news:eRNkIJzi...@TK2MSFTNGP05.phx.gbl...

thanks, it looks a bit diff in the newreader than ide i think
i'm pretty sure my tabs in the ide are set to two spaces but not sure it
copied over quite right.
will check that later
mark


Jim Mack

unread,
Jan 2, 2010, 3:27:32 PM1/2/10
to
As Larry noted, both of us were treating the low part as unsigned,
which of course is not possible with VB Longs. So there is the
drudgery of sign flipping or zero extension to accommodate the
situations where it exceeds 80000000H (where it appears to go negative
in VB).

Bottom line -- the idea is right for languages that have unsigned
longs, but incomplete for VB.

The simplest way to handle it is to switch everything to Currency.
Then you can do direct comparison. Currency is an 8-byte integer, just
like a FILETIME, except that it's scaled by 10000.

Wherever you have "As FILETIME" in an API call or structure, just
substitute "As Currency".

Then the comparison becomes simply:

Dim Diff As Currency, Delta As Currency

Delta = 2 * (10^3) ' 10^7 scaled by 10,000

Diff = TimeA - TimeB ' all Currency vars.

Result = 0

If Diff <> 0 Then


If Abs(Diff) > Delta Then
Select Case Sgn(Diff)
Case -1

Result = 2
Case 1
Result = 1
End Select
End If
End If


Maybe there's a more clever / elegant way of dealing with all this,
and if so Larry will probably post it. (-:

mp

unread,
Jan 2, 2010, 3:58:37 PM1/2/10
to
you guys never cease to amaze me!

"Jim Mack" <jm...@mdxi.nospam.com> wrote in message

news:uiPr$n%23iKH...@TK2MSFTNGP05.phx.gbl...


> As Larry noted, both of us were treating the low part as unsigned,
> which of course is not possible with VB Longs. So there is the
> drudgery of sign flipping or zero extension to accommodate the
> situations where it exceeds 80000000H (where it appears to go negative
> in VB).

> snip

>
> Maybe there's a more clever / elegant way of dealing with all this,
> and if so Larry will probably post it. (-:
>
> --
> Jim Mack
> Twisted tees at http://www.cafepress.com/2050inc
> "We sew confusion"
>

Thanks to everyone for these very informative and helpful gifts!
my little file comparitor class is very happy to have learned so much!!!

hope your new year is great!
thanks
mark


0 new messages