GetFileDate returns wrong time after DaylightSaving change

Windows specific forum
User avatar
Pierre Bellisle
User
User
Posts: 35
Joined: Wed Jun 27, 2018 5:12 am

Re: GetFileDate returns wrong time after DaylightSaving chan

Post by Pierre Bellisle »

Hi Camille,

1601-01-01 01:00:00 is the oldest time that a FILETIME variable can use.
In fact it correspond to the time ZERO. Maximum is around year 30,827.
As MS say: Contains a 64-bit value representing the number of 100-nanosecond intervals since January 1, 1601 (UTC).
When you got "1601-01-01", it is usually that the API GetFileTime could not get a valid time due to some error.
If I got a minute, I'll try to post some code that will tell the nature of the error...
User avatar
Pierre Bellisle
User
User
Posts: 35
Joined: Wed Jun 27, 2018 5:12 am

Re: GetFileDate returns wrong time after DaylightSaving chan

Post by Pierre Bellisle »

I edited my previous code to integrate verbose error checking plus a Boolean "FolderWanted" variable which let you choose between a file or folder.

Now, you should know the source of the error...
camille
User
User
Posts: 66
Joined: Tue Nov 19, 2019 12:52 pm

Re: GetFileDate returns wrong time after DaylightSaving chan

Post by camille »

Thank you, Pierre!

Code: Select all

FolderWanted is FALSE
Daylight saving is on
Daylight saving offset is -60 minutes
File name is R:\TEMP\~DFC5E820D9B2E4F0C0.TMP
CreateFile error: Error 32 (0x20) : The process cannot access the file because it is being used by another process.
File system for R:\ is NTFS
Local last write file time is 1601-01-01 01:00:00
Unfortunately, lockhunter says that's not the case and the inbuilt GetFileDate() doesn't have a problem with that as well.

Code: Select all

zExeName = "R:\TEMP\~DFC5E820D9B2E4F0C0.TMP"
Debug FormatDate("%yyyy.%mm.%dd %hh:%ii:%ss", GetFileDate(zExeName, #PB_Date_Modified))
2020.08.11 12:48:02
Is there any other way to create a handle to the file without using CreateFile_() or is there any way to tell it that it shouldn't care about any locks?
User avatar
Pierre Bellisle
User
User
Posts: 35
Joined: Wed Jun 27, 2018 5:12 am

Re: GetFileDate returns wrong time after DaylightSaving chan

Post by Pierre Bellisle »

Camille,

Try this, in CreateFile_(), replace #GENERIC_READ with 0 (Zero). It will be more permissive...
Last edited by Pierre Bellisle on Mon Sep 21, 2020 3:49 am, edited 1 time in total.
User avatar
Pierre Bellisle
User
User
Posts: 35
Joined: Wed Jun 27, 2018 5:12 am

Re: GetFileDate returns wrong time after DaylightSaving chan

Post by Pierre Bellisle »

Finally, to take another approach that may do better in your case.
Here is some code that use FindFirstFile_()
It is also shorter...

Code: Select all

;Read "File Times and Daylight Saving Time" at https://docs.microsoft.com/en-us/windows/win32/sysinfo/file-times
;_____________________________________________________________________________

Procedure.s WinError(ErrorCode.L) 
 Protected *BStr
 Protected *BStrData.String 
 Protected.s ErrorMessage
 Protected.l ErrorLen

 ErrorLen = FormatMessage_(#FORMAT_MESSAGE_FROM_SYSTEM | #FORMAT_MESSAGE_ALLOCATE_BUFFER, 
                           #Null$, ErrorCode, #Null$, @*BStr , #Null$, #Null$) 
 If ErrorLen 
   *BStrData.String = @*BStr
   ErrorMessage = *BStrData\s
   LocalFree_(*BStr)
   ProcedureReturn("Error " + Str(ErrorCode) + " (0x" + Hex(ErrorCode) + ") : " + Left(ErrorMessage, ErrorLen - 2))
 Else
   ProcedureReturn("Unknown error " + Str(ErrorCode) + " (0x" + Hex(ErrorCode) + ")")
 EndIf

EndProcedure
;_____________________________________________________________________________

Procedure.s FileTimeToInternationalTime(File_Time) 
 Protected Sys_Time.SystemTime

 FileTimeToSystemTime_(File_Time, @Sys_Time)
 ProcedureReturn(Str(Sys_Time\wyear)                 + "-" + RSet(Str(Sys_Time\wMonth), 2, "0") + "-" + 
                 RSet(Str(Sys_Time\wDay) ,   2, "0") + " " + RSet(Str(Sys_Time\wHour),  2, "0") + ":" + 
                 RSet(Str(Sys_Time\wMinute), 2, "0") + ":" + RSet(Str(Sys_Time\wSecond), 2, "0")) 
 
EndProcedure
;______________________________________________________________________________

 Define zExeName.s{#MAX_PATH}
 Define zFileSystem.s{20}
 Define zDrive.s{4}
 Define.s sBuffer
 Define.i hFile 
 Define.l LastError
 Define.FILETIME LastWriteTime
 Define.FILETIME FileTimeLocal
 Define.SYSTEMTIME SystemTimeLocal
 Define.TIME_ZONE_INFORMATION TimeZoneInfo
 Define.WIN32_FIND_DATA FileData ;File data structure    

 If GetTimeZoneInformation_(TimeZoneInfo) = #TIME_ZONE_ID_DAYLIGHT 
     sBuffer = sBuffer + "Daylight saving is on"
 Else ;#TIME_ZONE_ID_STANDARD
     sBuffer = sBuffer + "Daylight saving is off"
 EndIf
 sBuffer = sBuffer + #CRLF$ + #CRLF$ + "Daylight saving offset is " + Str(TimeZoneInfo\DaylightBias) + " minutes"  + #CRLF$ + #CRLF$
 
 zExeName = ProgramFilename() 

 ;If you want to get the parent folder else REM those two lines
 zExeName = GetPathPart(zExeName) ;To get folder only
 zExeName = Left(zExeName, Len(zExeName) -1) ;Remove last backslash
 
 zDrive   = Left(zExeName, 3)

 GetVolumeInformation_(zDrive, 0, 0, 0, 0, 0, @zFileSystem, SizeOf(zFileSystem))
 sBuffer = sBuffer + "File system for " + Left(zExeName, 3) + " is " + zFileSystem + #CRLF$ + #CRLF$ 

 sBuffer = sBuffer + "File name is " + zExeName + #CRLF$ + #CRLF$

 hFile = FindFirstFile_(zExeName, @FileData) ;Get files or folders 
 If hFile <> #INVALID_HANDLE_VALUE ;Make sure we have a valid handle
   LastWriteTime = FileData\ftLastWriteTime ; \ftCreationTime \ftLastAccessTime \ftLastWriteTime
   FindClose_(hFile) 
 Else
   LastError = GetLastError_()
   sBuffer = sBuffer + "FindFirstFile_ error: " + WinError(LastError) + #CRLF$ + #CRLF$ ;Show it in readable text
 EndIf

 FileTimeToSystemTime_(LastWriteTime, @SystemTimeLocal)                     ;Convert to local time part A
 SystemTimeToTzSpecificLocalTime_(#Null, SystemTimeLocal, @SystemTimeLocal) ;Convert to local time part B
 SystemTimeToFileTime_(SystemTimeLocal, @FileTimeLocal)                     ;Convert to local time part C

 sBuffer = sBuffer + "Local last write file time is " + FileTimeToInternationalTime(FileTimeLocal) 

 MessageBox_(#HWND_DESKTOP, sBuffer + #CRLF$, "File time", #MB_OK | #MB_TOPMOST)

;______________________________________________________________________________
;
camille
User
User
Posts: 66
Joined: Tue Nov 19, 2019 12:52 pm

Re: GetFileDate returns wrong time after DaylightSaving chan

Post by camille »

Many thanks, Pierre! :D

Both of your versions work flawlessly!

I've run it over a bunch of folders and files (both with locked ones as well) with 100% success rate.
User avatar
Pierre Bellisle
User
User
Posts: 35
Joined: Wed Jun 27, 2018 5:12 am

Re: GetFileDate returns wrong time after DaylightSaving chan

Post by Pierre Bellisle »

Great! :-)
highend
Enthusiast
Enthusiast
Posts: 123
Joined: Tue Jun 17, 2014 4:49 pm

Re: GetFileDate returns wrong time after DaylightSaving change

Post by highend »

May I ask:

If you already have:

Code: Select all

 FileTimeToSystemTime_(LastWriteTime, @SystemTimeLocal)                     ;Convert to local time part A
 SystemTimeToTzSpecificLocalTime_(#Null, SystemTimeLocal, @SystemTimeLocal) ;Convert to local time part B
 SystemTimeToFileTime_(SystemTimeLocal, @FileTimeLocal)                     ;Convert to local time part C
Why is it necessary to convert it "again" via the

Code: Select all

FileTimeToInternationalTime(File_Time)
procedure?
User avatar
Pierre Bellisle
User
User
Posts: 35
Joined: Wed Jun 27, 2018 5:12 am

Re: GetFileDate returns wrong time after DaylightSaving change

Post by Pierre Bellisle »

highend wrote: Fri May 20, 2022 7:17 pm Why is it necessary to convert it "again" via the FileTimeToInternationalTime(File_Time) procedure?
A little late since last May, still...

In fact, it is not necessary, for me the point was to convert a FileTime variable to another FileTime variable.Wich is done via FileTimeToSystemTime(), SystemTimeToTzSpecificLocalTime() and SystemTimeToFileTime().

FileTimeToInternationalTime() is meant solely as a common function to show a FileTime result in a human readable way and is not really part of the main logic conversion.

One may use only FileTimeToSystemTime() and SystemTimeToTzSpecificLocalTime() if the result need to be in SystemTime format.
Post Reply