Ordner, Datei(en) und Unterordner: Datums- und Zeitstempel manipulieren!
Eine Python-Applikation mit grafischer Benutzeroberfläche (GUI-PyQT6). Bei allen grafischen Oberflächen
habe ich immer den QT-Designer benutzt. Hier ist das jetzt anders! Nur eine Python-Datei.
Datums- und Zeitstempel von Dateien, Ordnern und Unterordnern manipulieren-wozu braucht man das?
Ich kann nur eine Erklärung liefern: Meine Webseite „apisur.neocities.org“ entwickle ich auf meinem PC.
Anschließend führe ich ein Update aus. Weil ja etliche Ordner und Dateien bereits vorhanden sind,
brauche ich eine chronologische Ordnung. Was ist NEU, was ist ALT? In Verbindung mit dem
Datei-Explorer, dessen Schalter auf „Änderungsdatum“ steht, habe ich immer den Überblick.
Was macht das Programm insgesamt? Es öffnet ein Fenster, indem du einen Ordner auswählst und
ein Datum mit Uhrzeit einstellst. Wenn du auf den grünen Button klickst, bekommen dieser Ordner
und alle Dateien und Unterordner darin genau dieses Datum als "letzte Änderung" eingetragen.
➡️ Ordner auswählen über einen Dialog (Button "Durchsuchen …").
➡️ Ziel-Datum/Uhrzeit über ein Datums-/Zeitfeld mit Kalender-Popup.
➡️ Checkbox für Erstellungszeit (nur unter Windows).
➡️ Sicherheitsabfrage vor dem Ausführen.
➡️ Fortschrittsbalken und Protokoll-Fenster, das jede geänderte Datei/jeden Ordner live anzeigt.
➡️ Läuft in einem separaten Thread, damit die Oberfläche während der Verarbeitung nicht einfriert
(wichtig bei sehr vielen Dateien).
Kurz gesagt: Ordner wählen → Datum wählen → Knopf drücken → im Hintergrund werden alle Dateien "umdatiert",
während du live im Protokoll mitverfolgen kannst, was passiert.
Zeile 15 bis 31:
Die Werkzeuge, die geladen werden! Das Programm "leiht" sich Bausteine von PyQt6 "fertige Fenster-Elemente wie
Buttons, Textfelder, Kalender usw." damit man nicht alles selbst programmieren muss.
Zeile 37 bis 60:
Die Funktion "set_creation_time_windows" Ein kleiner Zusatz nur für Windows: Normalerweise kann man mit Python
nur die "Änderungszeit" einer Datei setzen, nicht die "Erstellungszeit". Diese Funktion nutzt einen
Windows-Trick (über das Zusatzpaket pywin32), um auch das zu ermöglichen, aber nur, wenn du das
per Häkchen einschaltest.
Zeile 65 bis 68:
Die Funktion "setze_zeit". Das ist die eigentliche "Uhr umstellen"-Funktion für eine einzelne Datei oder
einen einzelnen Ordner.
Zeile 75 bis 113:
Der Worker (Hintergrund-Arbeiter). Das ist der wichtigste Teil für die Bedienbarkeit: Wenn ein Ordner sehr
viele Dateien enthält, würde das Ändern aller Zeiten ein paar Sekunden dauern. Ohne diesen Trick würde in
dieser Zeit das ganze Fenster "einfrieren" und nicht mehr reagieren. Der Worker erledigt die Arbeit deshalb
im Hintergrund, während das Fenster weiter bedienbar bleibt, den Fortschritt anzeigt und jede bearbeitete
Datei ins Protokoll schreibt.
Zeile 118 bis 266:
Das Hauptfenster (die eigentliche Oberfläche). Hier wird das sichtbare Fenster zusammengebaut:
➡️ Textfeld + "Durchsuchen"-Button → Ordner auswählen.
➡️ Kalenderfeld → Ziel-Datum/Uhrzeit einstellen.
➡️ Checkbox → Erstellungszeit mit ändern (nur Windows).
➡️ Grüner Button → startet den Vorgang (fragt vorher noch mal sicherheitshalber nach: "Bist du sicher?").
➡️ Fortschrittsbalken → zeigt, wie weit die Bearbeitung ist.
➡️ Textfeld unten → Protokoll, das live mitschreibt, was gerade geändert wird.
Zeile 271 bis 275:
Das ist der Startpunkt, hier wird das Fenster tatsächlich geöffnet und angezeigt, wenn du das
Script ausführst.
Tiefer ins Detail für Worker-Thread und Windows-Erstellungszeit:
Das Problem ohne Worker: Ein normales Programm arbeitet Zeile für Zeile ab, auch die Fensteranzeige selbst
muss sich "ständig neu zeichnen", um auf Mausklicks, Bewegen des Fensters usw. zu reagieren. Wenn du in der
starten()-Methode direkt anfängst, tausende Dateien zu bearbeiten, ist das Programm für diese Zeit komplett
damit beschäftigt, es hat keine "Zeit" mehr, das Fenster neu zu zeichnen. Das Fenster wirkt dann eingefroren
("Keine Rückmeldung").
Die Lösung: Ein zweiter "Arbeiter" läuft parallel. Man kann sich das wie zwei Personen vorstellen: Person A
(Hauptfenster/GUI-Thread): Kümmert sich nur ums Fenster, Klicks entgegennehmen, Anzeige aktualisieren.
Person B (Worker): Arbeitet nebenbei stur die Dateiliste ab, ohne sich um das Fenster zu kümmern. Im Script
ist das die Klasse Worker(QThread). Wichtige Punkte:
pythonclass Worker(QThread):
fortschritt = pyqtSignal(int, int)
log = pyqtSignal(str)
fertig = pyqtSignal(int, int, list).
Diese drei Zeilen definieren Signale,
das sind wie kleine "Zurufe", die der Worker an das Hauptfenster schicken darf, während er arbeitet:
fortschritt → "Ich bin jetzt bei Datei 42 von 300"
log → "Ich habe gerade Datei XY.txt geändert"
fertig → "Ich bin komplett fertig, hier die Ergebnisse"
Der Worker darf das Fenster nicht direkt anfassen
(das würde zu Chaos/Abstürzen führen), deshalb "ruft" er nur über diese Signale, und das Hauptfenster reagiert darauf, z. B. so:
pythonself.worker.log.connect(self.log_ausgabe.append). Das bedeutet: "Immer wenn der Worker das log-Signal sendet,
hänge den Text automatisch ans Protokollfenster an." Diese Verbindung heißt bei PyQt "Signal-Slot-Verbindung", ein zentrales Konzept.
Mit self.worker.start() wird Person B "losgeschickt", ab da läuft run() im Worker parallel, während das Hauptfenster
weiter normal reagiert.
Die Windows-Erstellungszeit, warum ein Extra-Trick nötig ist! Jede Datei hat eigentlich (mindestens)
drei Zeitstempel:
Änderungszeit (mtime): wann der Inhalt zuletzt geändert wurde.
Zugriffszeit (atime): wann die Datei zuletzt geöffnet/gelesen wurde.
Erstellungszeit: wann die Datei ursprünglich angelegt wurde. (nur unter Windows als eigener Wert gespeichert; Linux/macOS
kennen das über normale Bordmittel nicht in dieser Form).
Python hat dafür den eingebauten Befehl: os.utime(pfad, (zugriffszeit, aenderungszeit)).
Das funktioniert auf allen Betriebssystemen, aber es kann nur Zugriffs- und Änderungszeit setzen, nicht die Erstellungszeit.
Um unter Windows trotzdem die Erstellungszeit zu setzen, braucht man einen "Systemaufruf" direkt an Windows, das ist etwas, das
normales Python nicht mitbringt. Deshalb nutzt das Script das Zusatzpaket pywin32, das eine Brücke zu den Windows-eigenen
Programmierschnittstellen baut:
handle = win32file.CreateFile(...) # Datei "öffnen" auf Windows-Ebene
win32file.SetFileTime(handle, wintime, None, None) # Erstellungszeit setzen
handle.close()
Da dieses Paket nicht jeder installiert hat, ist der Code so geschrieben,
dass er es freundlich überspringt, falls pywin32 fehlt:
except ImportError:
pass
Das heißt: Kein Absturz, es wird einfach nur die Erstellungszeit nicht gesetzt,
Zugriffs-/Änderungszeit funktionieren trotzdem immer.
Wenn du magst, kann ich das Ganze auch an einem konkreten Beispiel-Ablauf durchspielen ("was passiert Schritt
für Schritt, wenn du auf den Button klickst"), das macht es oft noch greifbarer.
Ausgangssituation: Du hast einen Ordner ausgewählt (z. B. C:\Fotos\Urlaub) und ein Datum eingestellt
(z. B. 15.03.2026, 10:30 Uhr).
Schritt 1: Du klickst auf den grünen Button Das löst die Methode starten() aus (weil
sie vorher mit self.start_btn.clicked.connect(self.starten) "verdrahtet" wurde).
Schritt 2: Prüfungen! starten() schaut zuerst nach, ob überhaupt ein gültiger Ordner
eingetragen ist:
if not ordner or not os.path.isdir(ordner):
QMessageBox.warning(...)
return
Falls nicht → Warnmeldung, und alles stoppt hier.
Schritt 3: Datum umwandeln Das Kalenderfeld liefert intern ein QDateTime-Objekt
(PyQt-eigenes Format). Das wird in ein normales Python-datetime-Objekt umgewandelt, damit der Worker
später damit rechnen kann.
Schritt 4: Sicherheitsabfrage! Ein Dialogfenster fragt: "Datum/Uhrzeit von allen
Dateien … wird auf … gesetzt. Fortfahren?" Klickst du "Nein" → Abbruch, nichts passiert. Klickst du "Ja" → weiter.
Schritt 5: Vorbereitung der Oberfläche
self.log_ausgabe.clear()
self.fortschritt_balken.setValue(0)
self.start_btn.setEnabled(False)
Protokoll wird geleert, Fortschrittsbalken auf 0 gesetzt, und der Button wird deaktiviert (damit du nicht
während der Arbeit ein zweites Mal klickst, erkennbar auch an der helleren Farbe, die wir vorhin
gestylt haben).
Schritt 6: Der Worker wird erzeugt und losgeschickt:
self.worker = Worker(ordner, ziel_zeit, mit_erstellungszeit)
self.worker.start()
Ab jetzt läuft Person B (der Worker) im Hintergrund los, während das Fenster (Person A) weiter reagiert.
Schritt 7: Der Worker sammelt erstmal alle Pfade. Bevor er irgendetwas ändert, geht er einmal
komplett durch den Ordner (os.walk) und schreibt sich eine Liste aller Dateien und Unterordner
auf, z. B. 300 Stück. Das braucht er,
um zu wissen, wie lang der Fortschrittsbalken werden muss.
Schritt 8: Der Worker arbeitet die Liste ab. Für jede der 300 Dateien/Ordner, einer nach
dem anderen: Zeit setzen (setze_zeit(...)) "Ich bin jetzt bei Nummer 42 von 300" → Signal
fortschritt senden "Ich habe gerade Datei XY.jpg geändert" → Signal log senden.
Schritt 9: Das Hauptfenster reagiert live auf diese Signale. Jedes Mal, wenn ein Signal
ankommt, passiert sofort im Fenster: Fortschrittsbalken rückt ein Stückchen weiter. Neue Zeile erscheint im Protokoll-Textfeld.
Das sieht für dich so aus, als würde alles "live" mitgeschrieben, tatsächlich ist es der Worker, der ständig kleine
Meldungen rüberfunkt.
Schritt 10: Der Worker ist fertig. Nachdem alle 300 Einträge bearbeitet sind, sendet er
ein letztes Signal:
self.fertig.emit(anzahl_dateien, anzahl_ordner, fehler)
Schritt 11: Das Hauptfenster schließt ab. Die Methode
verarbeitung_fertig()wird aufgerufen: Button wird wieder aktiviert (wieder klickbar,
wieder grün). Eine Zusammenfassung wird ins Protokoll geschrieben ("Fertig! 280 Datei(en) und 20 Ordner aktualisiert.").
Ein Info-Fenster poppt auf mit derselben Meldung.
Zusammengefasst als Kette: Klick → Prüfen → Bestätigen → Button sperren → Worker
startet → Worker sammelt Liste → Worker arbeitet Stück für Stück ab und meldet sich laufend → Worker meldet
"fertig" → Fenster zeigt Ergebnis und entsperrt den Button wieder.
Für die grafische Benutzeroberfläche (PyQT5/6) habe ich vorher immer den QT-Designer benutzt. Nun habe ich die Oberfläche direkt in Python-Code geschrieben. Nachfolgend meine Beweggründe:
➡️ Alles an einem Ort, alles nachvollziehbar Layout, Logik (was beim Klick passiert) und Styling stehen in derselben
Datei, in derselben Sprache. Beim Qt-Designer entsteht eine separate .ui-Datei (XML-Format), die du dann entweder zur
Laufzeit lädst oder in Python-Code "übersetzen" musst (pyuic6). Das ist ein zusätzlicher Schritt und eine
zusätzliche Datei, die im Hinterkopf behalten werden muss.
➡️ Direkt lesbar und erklärbar. Wie du "weiter oben" gesehen hast, kann ich (oder du selbst später) jede Zeile Code
direkt erklären, "dieser Button ist grün, weil hier im Stylesheet #2e7d32 steht". Bei einer .ui-Datei aus dem Designer
ist das Ergebnis oft eine unübersichtliche XML-Struktur, die sich schlechter "mit einfachen Worten" erklären oder
gezielt anpassen lässt.
➡️ Änderungen sind präziser steuerbar. Ich wollte, dass der Button "markanter" wird! Konnte ich gezielt ein paar Zeilen
Stylesheet ergänzen. Im Designer würde man das meist über Property-Felder in der Seitenleiste einstellen, funktioniert
auch, ist aber weniger direkt nachvollziehbar dokumentiert und schwerer zu "versionieren".
➡️ Kein zusätzliches Tool nötig. Für code-basierte Oberflächen brauchst du nur Python + PyQt6. Der Qt-Designer ist ein
separates Programm, das installiert und bedient werden muss.
Wo der Qt-Designer trotzdem seine Stärken hat (fairerweise):
➡️ Visuelles, direktes Feedback: Du siehst sofort per Maus, wie es aussieht, ohne den Code laufen zu lassen, gerade bei
sehr komplexen, verschachtelten Layouts kann das schneller gehen.
➡️ Für Nicht-Programmierer geeigneter: Designer richtet sich auch an Menschen, die UI bauen, aber nicht unbedingt jede
Zeile Code selbst schreiben wollen.
➡️ Große, komplexe Formulare: Bei sehr vielen Feldern (z. B. 50+ Eingabefelder) kann Ziehen-und-Ablegen schneller
sein als alles einzeln zu programmieren.
Kurz gesagt: Für ein überschaubares, funktionales Tool wie meines hier ist der Code-Ansatz meist
übersichtlicher, besser erklärbar und leichter gezielt anpassbar, der Designer lohnt sich eher bei sehr großen, rein
visuell getriebenen Oberflächen.
Python Konsole!
Zu neunundneunzig Prozent schreibe ich immer zuerst eine „Python-Konsolen-Anwendung“, bevor ich mich mit der grafischen
Benutzeroberfläche (GUI) beschäftige! Dadurch habe ich einen großen Teil der Funktionen in trockenen Tüchern.
Auch sehe ich schon, wo die Reise hingeht. Oder! Ich bin total auf dem Holzweg!
Aufruf Programm (Beispiel): python datum_aendern.py "C:\Bilder\Garten" "04.07.2026 15:00:00"
Python file attribute changer © 2026 Hans Busche