Visual Basic File API Routines
SetFileTime: Modify the Date/Time of Folders and Files
Posted:   Saturday September 21, 2002
Updated:   Monday December 26, 2011
Applies to:   VB4-32, VB5, VB6
Developed with:   VB6, Windows XP
OS restrictions:   Windows NT/2000/XP
Author:   VBnet - Randy Birch


SetFileTime: Obtain and Change a File's Created, Accessed and Modified Dates
Windows NT4, Windows 2000 or Windows XP.

Changing the created, accessed or modified date of files or folders under Windows NT, 2000 or XP requires only a few simple API calls. By using CreateFile's special FILE_FLAG_BACKUP_SEMANTICS flag we can obtain a handle to a folder or file and, with SetFileTime, change its created, accessed or modified dates. When dealing with folders, the created date is reflected in the folder's property window, while Explorer shows the modified date (which under normal circumstances is always the same as the created date). Under Windows XP at least, the last accessed date of a folder is never shown.

To change the folder or file time, the SYSTEMTIME structure is populated with the day, month and year, and hour, minute and second of the desired date / time. However, when those values are used directly in a call to SetFileTime, Windows interprets the values passed as reflecting a Universal Coordinated Time (UTC) - aka a time at Greenwich mean time (GMT). In order for the date / time entered to be properly reflected with the SetFileTime call, the values contained in the SYSTEMTIME structure must first be converted to a FILETIME structure via SystemTimeToFileTime, and then the system must apply the local system's time-zone bias via LocalFileTimeToFileTime. Once the FILETIME structure has been changed, it is passed to SetFileTime and the new folder or file date / time is set.

Note that the code used in this method differs considerably from that used to change a file's created, accessed or modified date / time under Windows 9x (a method which is also applicable to NT-based machines), in that this method requires obtaining the folder's handle via CreateFile with the NT-specific FILE_FLAG_BACKUP_SEMANTICS flag set. The 9x-compatible method uses OpenFile to obtain the file handle where the FILE_FLAG_BACKUP_SEMANTICS flag is not supported.

Command1 ("New Date") is provided as a convenience to rapidly test this code and just calls a routine to randomly select values from the combo. Command2 ("Change Date") executes the APIs responsible for the date change.

 BAS Module Code

 Form Code
The form consists of three text boxes (Text1 - Text3), two command buttons (Command1, Command2) and six combo boxes (Combo1 - Combo6). Label as desired and add the following code:

Option Explicit
' Copyright 1996-2011 VBnet/Randy Birch, All Rights Reserved.
' Some pages may also contain other copyrights by the author.
' Distribution: You can freely use this code in your own
'               applications, but you may not reproduce 
'               or publish this code on any web site,
'               online service, or distribute as source 
'               on any media without express permission.
Private Const GENERIC_READ = &H80000000
Private Const GENERIC_WRITE = &H40000000
Private Const FILE_SHARE_READ = &H1
Private Const FILE_SHARE_DELETE As Long = &H4
Private Const FILE_FLAG_BACKUP_SEMANTICS = &H2000000
Private Const OPEN_EXISTING = 3

Private Type FILETIME
  dwLowDateTime     As Long
  dwHighDateTime    As Long
End Type

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

Private Declare Function CreateFile Lib "kernel32" _
   Alias "CreateFileA" _
  (ByVal lpFileName As String, _
   ByVal dwDesiredAccess As Long, _
   ByVal dwShareMode As Long, _
   ByVal lpSecurityAttributes As Long, _
   ByVal dwCreationDisposition As Long, _
   ByVal dwFlagsAndAttributes As Long, _
   ByVal hTemplateFile As Long) As Long

Private Declare Function CloseHandle Lib "kernel32" _
  (ByVal hObject As Long) As Long

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

Private Declare Function FileTimeToSystemTime Lib "kernel32" _
  (lpFileTime As FILETIME, _
   lpSystemTime As SYSTEMTIME) As Long

Private Declare Function SystemTimeToFileTime Lib "kernel32" _
  (lpSystemTime As SYSTEMTIME, _
   lpFileTime As FILETIME) As Long

Private Declare Function LocalFileTimeToFileTime Lib "kernel32" _
  (lpLocalFileTime As FILETIME, _
   lpFileTime As FILETIME) As Long

Private Declare Function SetFileTime Lib "kernel32" _
  (ByVal hFile As Long, _
   lpCreationTime As FILETIME, _
   lpLastAccessTime As Any, _
   lpLastWriteTime As Any) As Long

Private Sub Form_Load()

   Dim cnt As Long
   With Combo1
      For cnt = 1 To 31
         .AddItem cnt
   End With
   With Combo2
      For cnt = 1 To 12
         .AddItem MonthName(cnt)
         .ItemData(.NewIndex) = cnt
   End With
  'years (note: if you change this
  'range, also change the Combo3
  'random number maximum in
   With Combo3
      For cnt = 1980 To 2002
         .AddItem cnt
   End With
   With Combo4
      For cnt = 1 To 24
         .AddItem cnt
   End With
   With Combo5
      For cnt = 0 To 59
         .AddItem cnt
   End With
   With Combo6
      For cnt = 0 To 59
         .AddItem cnt
   End With
   Randomize Timer
   Call SelectNewTestDate
   Command1.Caption = "New Date"
   Command1.TabIndex = 0
   Command2.Caption = "Change Date"
End Sub

Private Sub Command1_Click()

  'select a new set of list indicies
   Call SelectNewTestDate
End Sub

Private Sub Command2_Click()

   Dim hFolder As Long
  'obtain handle to the folder specified
  'in Text1
   hFolder = GetFolderFileHandle(Text1.Text)
   If (hFolder <> 0) And (hFolder > -1) Then
     'show the current folder date/time info
      Call GetFolderFileDate(hFolder, Text2)
     'attempt to change the date/time to the
     'values set in the combos
      If ChangeFolderFileDate(hFolder) Then
        'show the new folder date/time info
         Call GetFolderFileDate(hFolder, Text3)
         Text3.Text = "ChangeFolderFileDate failed."
      End If
     'clean up. If hfolder = -1 on a subsequent
     'run, you didn't close the hFolder handle.
     'Save the project and exit VB to release
     'the handle, then restart VB and re-run.
      Call CloseHandle(hFolder)
      Text2.Text = "Specified folder/file not found"
   End If

End Sub

Private Function ChangeFolderFileDate(ByVal hFolder As Long) As Boolean

   Dim ft As FILETIME
  'set the day, month and year, and
  'the hour, minute and second to the
  'values representing the desired date/time
   With st
      .wDay = Combo1.List(Combo1.ListIndex)
      .wMonth = Combo2.ItemData(Combo2.ListIndex)
      .wYear = Combo3.List(Combo3.ListIndex)

      .wHour = Combo4.List(Combo4.ListIndex)
      .wMinute = Combo5.List(Combo5.ListIndex)
      .wSecond = Combo6.List(Combo6.ListIndex)
   End With
  'call SystemTimeToFileTime to convert the system
  'time (st) to a file time (ft)
   If SystemTimeToFileTime(st, ft) = 1 Then
     'call LocalFileTimeToFileTime to convert the
     'local file time to a file time based on the
     'Coordinated Universal Time (UTC). Conveniently, 
     'the same FILETIME can be used as the in/out 
      If LocalFileTimeToFileTime(ft, ft) = 1 Then
        'and call SetFileTime to set the date and
        'time that a file was created, last accessed,
        'and/or last modified (in this case all to
        'the same date/time). Since SetFileTime
        'returns 1 if successful, cast to return
        'a Boolean indicating failure or success.
         ChangeFolderFileDate = SetFileTime(hFolder, ft, ft, ft) = 1
      End If
   End If

End Function

Private Sub GetFolderFileDate(ByVal hFolder As Long, txt As TextBox)

   Dim buff As String
  'fill in the FILETIME structures for the
  'created, accessed and modified date/time info
   If GetFileTime(hFolder, FT_CREATE, FT_ACCESS, FT_WRITE) = 1 Then
      buff = "Created:" & vbTab & GetFolderFileDateString(FT_CREATE) & vbCrLf
      buff = buff & "Access'd:" & vbTab & GetFolderFileDateString(FT_ACCESS) & vbCrLf
      buff = buff & "Modified:" & vbTab & GetFolderFileDateString(FT_WRITE)
      txt.Text = buff
   End If
End Sub

Private Function GetFolderFileDateString(ft As FILETIME) As String

   Dim ds As Single
   Dim ts As Single
   Dim ft_local As FILETIME
  'convert the file time to a local
  'file time
   If FileTimeToLocalFileTime(ft, ft_local) Then
     'convert the local file time to
     'the system time format
      If FileTimeToSystemTime(ft_local, st) Then
        'calculate the DateSerial/TimeSerial 
        'values for the system time
         ds = DateSerial(st.wYear, st.wMonth, st.wDay)
         ts = TimeSerial(st.wHour, st.wMinute, st.wSecond)
        'and return a formatted string
         GetFolderFileDateString = FormatDateTime(ds, vbLongDate) & "  " & _
                                   FormatDateTime(ts, vbLongTime)
      End If
    End If
End Function

Private Function GetFolderFileHandle(sPath As String) As Long

  'open and return a handle to the folder
  'for modification.
  'valid on Windows NT/2000/XP, and is usually
  'used to indicate that the file (or folder) is
  'being opened or created for a backup or restore
  'operation. The system ensures that the calling
  'process overrides file security checks, provided
  'it has the necessary privileges (SE_BACKUP_NAME
  'In our case, specifying this flag obtains a handle to
  'a directory, and a directory handle can be passed to
  'some functions (e.g.. SetFileTime) in place of a file handle.
   GetFolderFileHandle = CreateFile(sPath, _
                                    GENERIC_READ Or GENERIC_WRITE, _
                                    FILE_SHARE_READ Or FILE_SHARE_DELETE, _
                                    0&, _
                                    OPEN_EXISTING, _
                                    FILE_FLAG_BACKUP_SEMANTICS, _
End Function

Private Sub SelectNewTestDate()

  'this just selects a new random
  'number for each combo, thereby
  'providing an easy test bed for
  'changing test dates
   Combo1.ListIndex = Int(Rnd * 31) 'days
   Combo2.ListIndex = Int(Rnd * 12) 'months
   Combo3.ListIndex = Int(Rnd * 23) 'years
   Combo4.ListIndex = Int(Rnd * 24) 'hours
   Combo5.ListIndex = Int(Rnd * 60) 'minutes
   Combo6.ListIndex = Int(Rnd * 60) 'seconds
End Sub
Run your project, and enter a valid folder or filename. This project does not prompt before changing, nor does it provide an undo, so take care applying it to valuable folders while testing.

Pressing the New Date button cycles through random date/times.  The Change button will update the folder or file specified, with the old file dates reflected in Text2, and the new dates after SetFileTime shown in Text3.


PayPal Link
Make payments with PayPal - it's fast, free and secure!


Copyright 1996-2011 VBnet and Randy Birch. All Rights Reserved.
Terms of Use  |  Your Privacy


Hit Counter