FileSetTime: Sommer-/Winterzeit? Topic is solved

Stelle Fragen zur Programmierung mit Autohotkey

Moderator: jNizM

User avatar
LuckyJoe
Posts: 340
Joined: 02 Oct 2013, 09:52

Re: FileSetTime: Sommer-/Winterzeit?

11 Dec 2018, 02:22

So, ein paar Tage erfolglos herumexperimentiert. Ich wusste nicht, dass die Zeitangabe offensichtlich so komplizert sein kann (oder ich sehe den Wald vor lauter Bäumen niocht mehr).
Das habe ich im Netz zum Setzen des Dateidatums gefunden:

1. https://docs.microsoft.com/de-de/window ... -file-time
Converting a time_t Value to a File Time
The time functions included in the C run-time use the time_t type to represent the number of seconds elapsed since midnight, January 1, 1970. The following example converts a time_t value to a file time, using the Int32x32To64 function (C+):

Code: Select all

#include <windows.h>
#include <time.h>

void TimetToFileTime( time_t t, LPFILETIME pft )
{
    LONGLONG ll = Int32x32To64(t, 10000000) + 116444736000000000;
    pft->dwLowDateTime = (DWORD) ll;
    pft->dwHighDateTime = ll >>32;
}

2. https://msdn.microsoft.com/de-de/librar ... s.85).aspx
FILETIME structure
Contains a 64-bit value representing the number of 100-nanosecond intervals since January 1, 1601 (UTC).

Code: Select all

typedef struct _FILETIME {
  DWORD dwLowDateTime;
  DWORD dwHighDateTime;
} FILETIME, *PFILETIME;

3. https://docs.microsoft.com/de-de/window ... rrent-time
Changing a File Time to the Current Time
The following example sets the last-write time for a file to the current system time using the SetFileTime function.
The NTFS file system stores time values in UTC format, so they are not affected by changes in time zone or daylight saving time. The FAT file system stores time values based on the local time of the computer.
The file must be opened with the CreateFile function using FILE_WRITE_ATTRIBUTES access.

Code: Select all

#include <windows.h>

// SetFileToCurrentTime - sets last write time to current system time
// Return value - TRUE if successful, FALSE otherwise
// hFile  - must be a valid file handle

BOOL SetFileToCurrentTime(HANDLE hFile)
{
    FILETIME ft;
    SYSTEMTIME st;
    BOOL f;

    GetSystemTime(&st);              // Gets the current system time
    SystemTimeToFileTime(&st, &ft);  // Converts the current system time to file time format
    f = SetFileTime(hFile,           // Sets last-write time of the file 
        (LPFILETIME) NULL,           // to the converted current system time 
        (LPFILETIME) NULL, 
        &ft);    

    return f;
}

4. https://docs.microsoft.com/en-us/window ... etfiletime
SetFileTime function
Sets the date and time that the specified file or directory was created, last accessed, or last modified.

Code: Select all

BOOL SetFileTime(
  HANDLE         hFile,
  const FILETIME *lpCreationTime,
  const FILETIME *lpLastAccessTime,
  const FILETIME *lpLastWriteTime
);

5. https://docs.microsoft.com/de-de/window ... reatefilea
CreateFileA function
Creates or opens a file or I/O device. The most commonly used I/O devices are as follows: file, file stream, directory, physical disk, volume, console buffer, tape drive, communications resource, mailslot, and pipe. The function returns a handle that can be used to access the file or device for various types of I/O depending on the file or device and the flags and attributes specified.
To perform this operation as a transacted operation, which results in a handle that can be used for transacted I/O, use the CreateFileTransacted function.

Code: Select all

HANDLE CreateFileA(
  LPCSTR                lpFileName,
  DWORD                 dwDesiredAccess,
  DWORD                 dwShareMode,
  LPSECURITY_ATTRIBUTES lpSecurityAttributes,
  DWORD                 dwCreationDisposition,
  DWORD                 dwFlagsAndAttributes,
  HANDLE                hTemplateFile
);

...so, alles schön in C+-Syntax, die ich nicht in AHK adaptieren kann. Gibt es hier jemanden, der da durchblickt und eine AHK-Funktion bauen kann, mit der ich das Datum einer Datei verändern kann? Idealerweise ähnlich der AHK-Funktion FileSetTime (M = Zeitpunkt der letzten Änderung / C = Zeitpunkt der Erstellung / A = Zeitpunkt des letzten Zugriffs), bei der ich die gewünschte Zeit "einfach" mit "TT.MM.JJJJ hh:mm:ss" übergeben kann.

Danke schon mal im Voraus.
HG - Lucky Joe
Herzliche Grüße aus dem Rheinland
Lucky Joe
just me
Posts: 9442
Joined: 02 Oct 2013, 08:51
Location: Germany

Re: FileSetTime: Sommer-/Winterzeit?

13 Dec 2018, 03:28

LuckyJoe wrote: ... bei der ich die gewünschte Zeit "einfach" mit "TT.MM.JJJJ hh:mm:ss" übergeben kann.
Nö! Aber vielleicht reicht Dir auch JJJJMMTThhmmss (bzw. YYYYMMDDHH24MISS)?

Das Übersetzen von Systemzeit in lokale Zeit und umgekehrt lässt sich nicht immer mit einem Funktionsaufruf erledigen. Bei den für Dateien gespeicherten Zeiten ist Microsoft wohl davon ausgegangen, dass bei Änderungen sogut wie immer die aktuelle Zeit benutzt wird. Das ist nachvollziehbar und AHK hat sich dieser Auffassung angeschlossen, wenn vielleicht auch nur deswegen, weil 16-Bit Windows Versionen wie z.B. Win95 nur sehr rudimentäre API-Funktionen anboten.

Die folgende Funktion scheint Sommer- bzw. Winterzeit zumindest dann korrekt zu behandeln, wenn die Zeit im aktuellen Jahr liegt. Weiter habe ich das nicht getestet.

Code: Select all

#NoEnv
FilePath := A_ScriptDir . "\SetTime.txt"
If FileExist(FilePath)
   FileDelete, %FilePath%
FileAppend, %A_Now%, %FilePath%
SetFileTime(FilePath, 20180615151525, "C")
ExitApp
; ======================================================================================================================
; SetFileTime
;     -> docs.microsoft.com/en-us/windows/desktop/api/fileapi/nf-fileapi-setfiletime
; TzSpecificLocalTimeToSystemTime
;     -> docs.microsoft.com/en-us/windows/desktop/api/timezoneapi/nf-timezoneapi-tzspecificlocaltimetosystemtime
; SystemTimeToFileTime
;     -> docs.microsoft.com/en-us/windows/desktop/api/timezoneapi/nf-timezoneapi-systemtimetofiletime
; CreateFile
;     -> docs.microsoft.com/en-us/windows/desktop/api/fileapi/nf-fileapi-createfilea
;     FILE_WRITE_ATTRIBUTES 0x0100
;     FILE_SHARE_READ       0x01 +
;     FILE_SHARE_WRITE      0x02 +- 0X07
;     FILE_SHARE_DELETE     0x04 +
;     OPEN_EXISTING         3
;     FILE_ATTRIBUTE_NORMAL 0x80
; ======================================================================================================================
SetFileTime(FilePath, TimeStamp, Type := "M") {
   If !TimeStamp2SystemTime(TimeStamp, LocalTime)
      Return False
   If !(Handle := DllCall("CreateFile", "Str", FilePath, "UInt", 0x0100, "UInt", 0x07, "Ptr", 0
                                      , "UInt", 3, "UInt", 0x80, "Ptr", 0, "UPtr"))
      Return False
   VarSetCapacity(SystemTime, 16, 0)
   DllCall("TzSpecificLocalTimeToSystemTime", "Ptr", 0, "Ptr", &LocalTime, "Ptr", &SystemTime, "UInt")
   VarSetCapacity(FileTime, 8, 0)
   DllCall("SystemTimeToFileTime", "Ptr", &SystemTime, "Ptr", &FileTime, "UInt")
   CTime := Type = "C" ? &FileTime : 0
   ATime := Type = "A" ? &FileTime : 0
   MTime := Type = "M" ? &FileTime : 0
   Result := DllCall("SetFileTime", "Ptr", Handle, "Ptr", CTime, "Ptr", ATime, "Ptr", MTime, "UInt")
   DllCall("CloseHandle", "Ptr", Handle, "UInt")
   Return Result
}
; ======================================================================================================================
; TimeStamp = YYYYMMDDHH24MISS (autohotkey.com/docs/commands/FileSetTime.htm#YYYYMMDD)
; SystemTime -> msdn.microsoft.com/en-us/f77cdf86-0f97-4a89-b565-95b46fa7d65b
; ======================================================================================================================
TimeStamp2SystemTime(TimeStamp, ByRef SystemTime) {
   VarSetCapacity(SystemTime, 16, 0)
   TimeStamp += 0, S
   If (TimeStamp = "")
      Return False
   NumPut(SubStr(TimeStamp,  1, 4), SystemTime,  0, "UShort")
   NumPut(SubStr(TimeStamp,  5, 2), SystemTime,  2, "UShort")
   NumPut(SubStr(TimeStamp,  7, 2), SystemTime,  6, "UShort")
   NumPut(SubStr(TimeStamp,  9, 2), SystemTime,  8, "UShort")
   NumPut(SubStr(TimeStamp, 11, 2), SystemTime, 10, "UShort")
   NumPut(SubStr(TimeStamp, 13, 2), SystemTime, 12, "UShort")
   Return True
}
User avatar
LuckyJoe
Posts: 340
Joined: 02 Oct 2013, 09:52

Re: FileSetTime: Sommer-/Winterzeit?

13 Dec 2018, 05:28

Hallo justme,

... wow - ich bin mal wieder tief beeindruckt! Chapeau!
Danke für die Funktionen, die hätte ich alleine nie hinbekommen.
Die Zeiten kann man nicht nur für das aktuelle Jahr verwenden, sondern zurück bis zum 01.01.1601, 01:00:01. ;-)

Zwei Fragen dazu:

1.
Wenn ich bei einer bestehenden Datei (nicht neu erstellte) die Erstellungszeit ("C") oder die Zeit des letzten Zugriffs ("A") ändere, wird der Zeitstempel für die letzte Änderung ("M") immer auf die Zeit der Programmausführung (spich auf "jetzt") gesetzt. Liest sich das zu kompliziert? Beispiel:

SetTime.txt hat folgende Zeitstempel:

Code: Select all

Erstellt ("C"): 01.01.2018, 01:01:01
geändert ("M"):	02.02.2018, 02:02:02
letzter Zugriff ("A"): 03.03.2018, 03:03:03
Mit Aufruf SetFileTime(FilePath, 20180303030303, "A") wird der letzte Zugriffszeit wunschgemäß geändert, aber gleichzeitig "geändert" auf heute gesetzt.
Ebenso wird mit Aufruf SetFileTime(FilePath, 20180101010101, "C") die Erstellungszeit wunschgemäß geändert, aber gleichzeitig wiederum "geändert" auf heute gesetzt.

Wie muss die Funktion aussehen, wenn ich die Zeit der letzten Änderung ("M") "unangetastet", also den bestehenden Zeitstempel dafür ungeändert lassen möchte (vlt. mit zusätzlichem (boolschem) Parameter)?

2.
Bei der Funktion

Code: Select all

SetFileTime(FilePath, TimeStamp, Type := "M") {
...
}
ist mir das Type := "M" nicht ganz klar. Bezieht sich das auf den Buchstaben, der mit dem Funktionsaufruf korresponiert oder korrespondieren soll? Bei meinen Testaufrufen ändert sich überhaupt nichts, wenn ich dort "A", "C", "M", "X" oder irgendeinen anderen Buchstaben verwende.

HG - Lucky Joe
Herzliche Grüße aus dem Rheinland
Lucky Joe
just me
Posts: 9442
Joined: 02 Oct 2013, 08:51
Location: Germany

Re: FileSetTime: Sommer-/Winterzeit?  Topic is solved

14 Dec 2018, 04:52

Moin LuckyJoe,
  1. ...
    Versuch mal diese Version der Funktion:

    Code: Select all

    ; ======================================================================================================================
    ; SetFileTime
    ;     -> docs.microsoft.com/en-us/windows/desktop/api/fileapi/nf-fileapi-setfiletime
    ; TzSpecificLocalTimeToSystemTime
    ;     -> docs.microsoft.com/en-us/windows/desktop/api/timezoneapi/nf-timezoneapi-tzspecificlocaltimetosystemtime
    ; SystemTimeToFileTime
    ;     -> docs.microsoft.com/en-us/windows/desktop/api/timezoneapi/nf-timezoneapi-systemtimetofiletime
    ; CreateFile
    ;     -> docs.microsoft.com/en-us/windows/desktop/api/fileapi/nf-fileapi-createfilea
    ;     FILE_WRITE_ATTRIBUTES 0x0100
    ;     FILE_SHARE_READ       0x01 +
    ;     FILE_SHARE_WRITE      0x02 +- 0X07
    ;     FILE_SHARE_DELETE     0x04 +
    ;     OPEN_EXISTING         3
    ;     FILE_ATTRIBUTE_NORMAL 0x80
    ; ======================================================================================================================
    SetFileTime(FilePath, TimeStamp, Type := "M") {
       If !TimeStamp2SystemTime(TimeStamp, LocalTime)
          Return False
       If !(Handle := DllCall("CreateFile", "Str", FilePath, "UInt", 0x0100, "UInt", 0x07, "Ptr", 0
                                          , "UInt", 3, "UInt", 0x80, "Ptr", 0, "UPtr"))
          Return False
       ; Aktuelle Daten einlesen
       VarSetCapacity(CTime, 16, 0)
       VarSetCapacity(ATime, 16, 0)
       VarSetCapacity(MTime, 16, 0)
       If !DllCall("GetFileTime", "Ptr", Handle, "Ptr", &CTime, "Ptr", &ATime, "Ptr", &MTime, "UInt") {
          DllCall("CloseHandle", "Ptr", Handle, "UInt")
          Return False
       }
       ; Geändertes Datum schreiben
       VarSetCapacity(SystemTime, 16, 0)
       DllCall("TzSpecificLocalTimeToSystemTime", "Ptr", 0, "Ptr", &LocalTime, "Ptr", &SystemTime, "UInt")
       VarSetCapacity(FileTime, 8, 0)
       DllCall("SystemTimeToFileTime", "Ptr", &SystemTime, "Ptr", &FileTime, "UInt")
       PCT := Type = "C" ? &FileTime : &CTime
       PAT := Type = "A" ? &FileTime : &ATime
       PMT := Type = "M" ? &FileTime : &MTime
       Result := DllCall("SetFileTime", "Ptr", Handle, "Ptr", PCT, "Ptr", PAT, "Ptr", PMT, "UInt")
       DllCall("CloseHandle", "Ptr", Handle, "UInt")
       Return Result
    }
  2. ...
    Type := "M" bestimmt den Standardwert des Parameters. Dieser Wert (hier M) wird verwendet, wenn der Parameter im Funktionsaufruf weggelassen wird.
User avatar
LuckyJoe
Posts: 340
Joined: 02 Oct 2013, 09:52

Re: FileSetTime: Sommer-/Winterzeit?

14 Dec 2018, 11:03

... jepp - perfekt :-)
Danke dir, auch für die Aufklärung über den Parameter.
Herzliche Grüße aus dem Rheinland
Lucky Joe

Return to “Ich brauche Hilfe”

Who is online

Users browsing this forum: LuckyJoe and 26 guests