Page 1 of 2
GetFileDate returns wrong time after DaylightSaving change
Posted: Mon Oct 28, 2013 11:00 pm
by nalor
Hi!
Yesterday I came accross a strange bug (at least I think it's a bug as I can't see any logic in the current behaviour).
When I use 'GetFileDate' to read the '#PB_Date_Modified' Date of a file I get different results depending on the DaylightSaving status.
For example the 5.20 x86 purebasic.exe:
GetFileDate returns >1379419754< >2013.09.17 12:09:14< when run with a systemdate BEFORE the daylight-saving change on 27.10.2013 (at least here in Austria), and when I change the systemdate to the current date (after the daylight saving change) I get a different result: >1379416154< >2013.09.17 11:09:14<
Personally I think 'GetFileDate' should always return the same value - regardless of the current daylight saving state.
When I check the modified date directly in windows explorer I'll get always the same result, independent of the current system date (always with 12:09).
So I've wrote a small workaround procedure 'GetFileDateTZ':
(based on the 'Remarks' here:
http://msdn.microsoft.com/en-us/library ... 85%29.aspx)
Code: Select all
EnableExplicit
Procedure.i GetFileDateTZ(Filename.s, Datetype.i, UseUTC.b=#False)
Protected FileHdl.i
Protected Create.FILETIME
Protected Access.FILETIME
Protected Write.FILETIME
Protected SystemTime.SYSTEMTIME
Protected LocalTime.SYSTEMTIME
FileHdl = ReadFile(#PB_Any, Filename)
If FileHdl
If Not GetFileTime_(FileID(FileHdl), @Create, @Access, @Write)
Debug "GetFileDateTZ - GetFileTime Error!!"
ProcedureReturn 0
EndIf
CloseFile(FileHdl)
Select Datetype
Case #PB_Date_Created
If Not FileTimeToSystemTime_(@Create, @SystemTime)
Debug "GetFileDateTZ - FileTimeToSystemTime Error!!"
EndIf
Case #PB_Date_Accessed
If Not FileTimeToSystemTime_(@Access, @SystemTime)
Debug "GetFileDateTZ - FileTimeToSystemTime Error!!"
EndIf
Case #PB_Date_Modified
If Not FileTimeToSystemTime_(@Write, @SystemTime)
Debug "GetFileDateTZ - FileTimeToSystemTime Error!!"
EndIf
Default
Debug "GetFileDateTZ - Invalid Datetype >"+Str(Datetype)+"<"
ProcedureReturn 0
EndSelect
If UseUTC
LocalTime=SystemTime
Else
If Not SystemTimeToTzSpecificLocalTime_(#Null, @SystemTime, @LocalTime)
Debug "GetFileDateTZ - SystemTimeToTzSpecificLocalTime Error!!"
ProcedureReturn 0
EndIf
EndIf
ProcedureReturn Date(LocalTime\wYear, LocalTime\wMonth, LocalTime\wDay, LocalTime\wHour, LocalTime\wMinute, LocalTime\wSecond)
Else
Debug "GetFileDateTZ - ReadFile Error!!"
ProcedureReturn 0
EndIf
EndProcedure
Define FileTime.i
Define sFile.s=#PB_Compiler_Home+"\purebasic.exe"
FileTime=GetFileDate(sFile, #PB_Date_Modified)
Debug "GetFileDate: >"+Str(FileTime)+"< >"+FormatDate("%yyyy.%mm.%dd %hh:%ii:%ss", FileTime)+"<"
FileTime=GetFileDateTZ(sFile, #PB_Date_Modified)
Debug "GetFileDateTZ: >"+Str(FileTime)+"< >"+FormatDate("%yyyy.%mm.%dd %hh:%ii:%ss", FileTime)+"<"
FileTime=GetFileDateTZ(sFile, #PB_Date_Modified, #True)
Debug "GetFileDateTZ: (UTC) >"+Str(FileTime)+"< >"+FormatDate("%yyyy.%mm.%dd %hh:%ii:%ss", FileTime)+"<"
When searching the forum for known problems with 'GetFileDate' I found this one:
http://www.purebasic.fr/english/viewtopic.php?t=50902 and so I've included also a parameter to my 'GetFileDateTZ' procedure that allows to get the date as UTC - this way it not even changes in case the local timezone is changed.
Until it's fixed I'll use my workaround
Edit: Changed the procedure slightly, removed the check for filesize, this almost doubled the speed (it's still slower than the original GetFileDate - but fast enough for all my purposes)
Re: GetFileDate returns wrong time after DaylightSaving chan
Posted: Mon Oct 28, 2013 11:26 pm
by Little John
This is a known problem, caused by the NTFS file system: Files created in summer (when daylight saving time is in effect) show a wrong time stamp in winter (when daylight saving time is not in effect), and vice versa. When using FAT32, then you'll not encounter this problem.
I did not check the details what PB exactly does in this context, but it probably just retrieves the time stamp from the file system.
Re: GetFileDate returns wrong time after DaylightSaving chan
Posted: Mon Oct 28, 2013 11:37 pm
by nalor
Hi LittleJohn!
I tried what you've suggested and copied the purebasic.exe to a FAT32 volume and now I'll get always a constant date: 2013.09.17 11:09:14
but my windows explorer still tells me it has been changed at 12:09
So to be honest I came to the conclusion that I cannot trust the return value of GetFileDate... it's neither the time I see in my explorer nor the UTC time - so I don't know what time it should be...
Re: GetFileDate returns wrong time after DaylightSaving chan
Posted: Tue Oct 29, 2013 12:00 am
by Little John
Hi nalor,
unfortunately I currently don't have the time to go into details. E.g.
this article provides some background information which might be of interest for you.
Re: GetFileDate returns wrong time after DaylightSaving chan
Posted: Tue Oct 29, 2013 1:34 pm
by utopiomania
I use this code:
Code: Select all
protected time.FILETIME, locTime.FILETIME, sysTime.SYSTEMTIME
id = readFile(0, path)
select when
case 0 ;created
getFileTime_(id, time, 0, 0)
case 1 ;accessed
getFileTime_(Id, 0, time, 0)
case 2 ;modified/written
getFileTime_(id, 0, 0, time)
endSelect
;correct for daylight savings in effect
fileTimeToLocalFileTime_(time, locTime)
fileTimeToSystemTime_(locTime, sysTime)
closeFile(0)
Re: GetFileDate returns wrong time after DaylightSaving chan
Posted: Tue Oct 29, 2013 6:49 pm
by nalor
Hi again!
@utopiomania:
I've tried your code - but I think it does the same as the internal 'GetFileDate' function because this is my result:
[18:40:37] GetFileDate: >1379416154< >2013.09.17 11:09:14<
[18:40:37] GetFileDateTZ: >1379419754< >2013.09.17 12:09:14<
[18:40:37] GetFileDateTZ: (UTC) >1379412554< >2013.09.17 10:09:14<
[18:40:37] GetFileDateTZ2: >1379416154< >2013.09.17 11:09:14<
Your version is the one labelled 'GetFileDateTZ2' - it shows exactly the same (wrong) time as the internal function.
The link that posted LittleJohn gives the explanation for this incorrect behaviour:
To convert a file time to local time, use the FileTimeToLocalFileTime function. However, FileTimeToLocalFileTime uses the current settings for the time zone and daylight saving time. Therefore, if it is daylight saving time, it takes daylight saving time into account, even if the file time you are converting is in standard time.
So using 'FileTimeToLocalTime' is never reliable when used in conjunction with daylight saving...
Re: GetFileDate returns wrong time after DaylightSaving chan
Posted: Wed Oct 30, 2013 10:45 am
by Fred
As it seems to be a Windows glitch, I moved this topic out of the bug forum
Re: GetFileDate returns wrong time after DaylightSaving chan
Posted: Wed Oct 30, 2013 5:01 pm
by utopiomania
nalor, the code I posted from copies files from cameras, and renames them according to their write date/time stamp onto pc's with or without daylight savings in effect, and does it correctly.
Without the conversions below the filenames was one hour wrong half of the year, but maybe that is a different problem than yours.
Code: Select all
;correct for daylight savings in effect
fileTimeToLocalFileTime_(time, locTime)
fileTimeToSystemTime_(locTime, sysTime)
Re: GetFileDate returns wrong time after DaylightSaving chan
Posted: Wed Oct 30, 2013 7:51 pm
by nalor
To be honest - I have a solution that works for me and so I can live with it - but I'd still expect that 'GetFileDate' returns the same timestamp as I can see directly in the explorer in windows.
Everything else is wrong in my eyes.
@Fred : And so I still think it's a bug in your GetFileDate implementation and not a glitch in windows because Microsoft clearly defines how it should be done correct (in the remarks section:
http://msdn.microsoft.com/en-us/library ... 85%29.aspx ).
And my small workaround procedure does it as microsoft says and I get the correct value.
@utopiomania : nothing against your code, if it works for you it's fine, but when use it I get wrong results.
My Windows Explorer tells me the purebasic.exe of 5.20 has been changed on >2013.09.17 12:09:14<, so this is the result I'd expect, but the only reliable way is as I got it from the MS page (GetFileDateTZ):
Summertime on my system (2013.10.01 systemdate)
NTFS volume:
[19:44:08] GetFileDate: >1379419754< >2013.09.17 12:09:14<
[19:44:08] GetFileDateTZ: >1379419754< >2013.09.17 12:09:14<
[19:44:08] GetFileDateTZ2: >1379419754< >2013.09.17 12:09:14<
FAT32 volume:
[19:43:29] GetFileDate: >1379419754< >2013.09.17 12:09:14<
[19:43:29] GetFileDateTZ: >1379419754< >2013.09.17 12:09:14<
[19:43:29] GetFileDateTZ2: >1379419754< >2013.09.17 12:09:14<
Wintertime on my system (2013.10.30 systemdate):
NTFS volume:
[19:44:56] GetFileDate: >1379416154< >2013.09.17 11:09:14<
[19:44:56] GetFileDateTZ: >1379419754< >2013.09.17 12:09:14<
[19:44:56] GetFileDateTZ2: >1379416154< >2013.09.17 11:09:14<
FAT32 volume:
[19:37:38] GetFileDate: >1379419754< >2013.09.17 12:09:14<
[19:37:38] GetFileDateTZ: >1379419754< >2013.09.17 12:09:14<
[19:37:38] GetFileDateTZ2: >1379416154< >2013.09.17 11:09:14<
As last time 'GetFileDateTZ2' is your implementation, as you can see during wintertime it's still 1 hour off...
Finally I can say: GetFileDate returns wrong results during wintertime on NTFS volumes.
Re: GetFileDate returns wrong time after DaylightSaving chan
Posted: Sat Aug 08, 2020 9:19 pm
by camille
Does anyone know how to change the code from the first post so that it works for folders instead of files?
Re: GetFileDate returns wrong time after DaylightSaving chan
Posted: Sun Aug 09, 2020 7:10 pm
by nalor
camille wrote:Does anyone know how to change the code from the first post so that it works for folders instead of files?
I haven't tried - but I think it should with folders out of the box - simply because the windows api command 'getfiledate' is also designed to work with folders:
https://docs.microsoft.com/en-us/window ... etfiletime
Does it return something wrong for you? Can you post an example what is wrong?
Re: GetFileDate returns wrong time after DaylightSaving chan
Posted: Sun Aug 09, 2020 8:42 pm
by camille
Output:
Code: Select all
GetFileDate: >1460658816< >2016.04.14 18:33:36<
GetFileDateTZ: >1460658816< >2016.04.14 18:33:36<
GetFileDateTZ: (UTC) >1460651616< >2016.04.14 16:33:36<
Now with the belonging folder:
Output:
Code: Select all
GetFileDate: >1592905274< >2020.06.23 09:41:14<
GetFileDateTZ - ReadFile Error!!
GetFileDateTZ: >0< >1970.01.01 00:00:00<
GetFileDateTZ - ReadFile Error!!
GetFileDateTZ: (UTC) >0< >1970.01.01 00:00:00<
I've found a way that works with both files and folders but this way has its own problems.
GetFileDate() is more reliable (though not 100%) on files in the %TEMP% folder and only reports 0 for some files / folders
while the api way reports 0 for more (maybe 10%) files / folders...
If you want to try it, replace this:
Code: Select all
FileHdl = ReadFile(#PB_Any, Filename)
If FileHdl
If Not GetFileTime_(FileID(FileHdl), @Create, @Access, @Write)
ProcedureReturn 0
EndIf
CloseFile(FileHdl)
with this:
Code: Select all
FileHdl = CreateFile_(path,
#GENERIC_READ|#GENERIC_WRITE,
#FILE_SHARE_READ|#FILE_SHARE_DELETE,
0,
#OPEN_EXISTING,
#FILE_FLAG_BACKUP_SEMANTICS,
0)
If FileHdl
If Not GetFileTime_(FileHdl, @Create, @Access, @Write)
ProcedureReturn 0
EndIf
CloseHandle_(FileHdl)
Re: GetFileDate returns wrong time after DaylightSaving chan
Posted: Tue Aug 11, 2020 6:11 am
by Pierre Bellisle
On my side I do not see any Windows glitch. Either on NTFS or FAT.
Use the Microsoft recommend way. See
File Times - File Times and Daylight Saving Time
FileTimeToSystemTime, SystemTimeToTzSpecificLocalTime and SystemTimeToFileTime
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 SelfExeName() ;GetExeNameGetFileNameFullFilename
Protected zExeName.s{#MAX_PATH}
GetModuleFileName_(GetModuleHandle_(0), @zExeName, #MAX_PATH) ;Get exe full name
ProcedureReturn(zExeName) ;
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.l FolderWanted
Define.FILETIME LastWriteTime
Define.FILETIME FileTimeLocal
Define.SYSTEMTIME SystemTimeLocal
Define.TIME_ZONE_INFORMATION TimeZoneInfo
FolderWanted = 001
If FolderWanted
sBuffer = "FolderWanted is TRUE" + #CRLF$ + #CRLF$
Else
sBuffer = "FolderWanted is FALSE" + #CRLF$ + #CRLF$
EndIf
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$
GetModuleFileName_(GetModuleHandle_(0), @zExeName, #MAX_PATH) ;Get exe full name ;Also Result$ = ProgramFilename()
If FolderWanted
zExeName = GetPathPart(zExeName) ;To get folder time
EndIf
;;For test... zExeName = zExeName + ".Error"
sBuffer = sBuffer + #CRLF$ + "File name is " + zExeName + #CRLF$ + #CRLF$
If FolderWanted
hFile = CreateFile_(zExeName, #FILE_LIST_DIRECTORY, #FILE_SHARE_READ, 0, #OPEN_EXISTING, #FILE_FLAG_BACKUP_SEMANTICS, 0)
Else
hFile = CreateFile_(zExeName, #GENERIC_READ, #FILE_SHARE_READ, 0, #OPEN_EXISTING, #FILE_ATTRIBUTE_NORMAL, 0)
EndIf
If hFile = #INVALID_HANDLE_VALUE ;An error occured
LastError = GetLastError_() ;Get error id
sBuffer = sBuffer + "CreateFile error: " + WinError(LastError) + #CRLF$ + #CRLF$ ;Shot it in readable text
Else ;Handle is good
If GetFileTime_(hFile, 0, 0, @LastWriteTime) = 0 ;Some error occured
LastError = GetLastError_() ;Get error id
;;LastError = 5 ;Test error id
sBuffer = sBuffer + "GetFileTime error: " + WinError(LastError) + #CRLF$ + #CRLF$ ;Shot it in readable text
EndIf
CloseHandle_(hFile)
EndIf
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$
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 + #CRLF$ + "Local last write file time is " + FileTimeToInternationalTime(FileTimeLocal)
MessageBox_(#HWND_DESKTOP, sBuffer + #CRLF$, "File time", #MB_OK | #MB_TOPMOST)
;______________________________________________________________________________
;
Re: GetFileDate returns wrong time after DaylightSaving chan
Posted: Tue Aug 11, 2020 6:38 am
by Pierre Bellisle
Note to use the code on a folder instead of a filename.
As example, REM out
;GetModuleFileName_(GetModuleHandle_(0), @zExeName, #MAX_PATH) ;Get exe full name
and add just after...
zExeName = "C:\Windows" ;Use what you want...
REM out
;hFile = CreateFile_(zExeName, #GENERIC_READ, #FILE_SHARE_READ, 0, #OPEN_EXISTING, #FILE_ATTRIBUTE_NORMAL, 0)
And add just after...
hFile = CreateFile_(zExeName, #FILE_LIST_DIRECTORY, #FILE_SHARE_READ, 0, #OPEN_EXISTING, #FILE_FLAG_BACKUP_SEMANTICS, 0)
Re: GetFileDate returns wrong time after DaylightSaving chan
Posted: Tue Aug 11, 2020 9:02 am
by camille
Hi Pierre,
Code: Select all
Daylight saving is on
Daylight saving offset is -60 minutes
File name is R:\TEMP\~DF4393CAED6853E7CB.TMP
File system for R:\ is NTFS
Local last write file time is 1601-01-01 01:00:00
Code: Select all
Daylight saving is on
Daylight saving offset is -60 minutes
File name is R:\TEMP\~DFE9BD699FAE1B9233.TMP
File system for R:\ is NTFS
Local last write file time is 2020-08-11 09:33:02
So at least on my side there are glitches...
Btw, the real last write time for the first file is: 2020-08-11 09:40:31
My guess is that there is some lock on the first file but "LockHunter" (
https://lockhunter.com/) doesn't report one.
Don't know why the code shows 1601-01-01 01:00:00 for that file. Windows Explorer and all other file manager show the correct date + time.