Eine Hintergrundaufgabe für „täglich um 02:30 Uhr Ortszeit synchronisieren“ kann an gewöhnlichen Tagen problemlos laufen und bei der Zeitumstellung dennoch ausfallen oder doppelt ausgeführt werden. Kapseln Sie deshalb zunächst auf einem Cloud-Mac die Berechnung des nächsten Ausführungszeitpunkts als reine Funktion und prüfen Sie sie mit festen Testdaten. Binden Sie erst danach Benachrichtigungen oder die Hintergrundplanung an. Geprüft wird hier der Vertrag der Kalenderberechnung – nicht der Zeitpunkt, zu dem das Betriebssystem die App tatsächlich aufweckt.
Lokale Uhrzeit und verstrichene Zeit unterscheiden
„Alle vierundzwanzig Stunden“ und „täglich um 02:30 Uhr“ sind zwei unterschiedliche Regeln. Die erste zählt verstrichene Sekunden weiter, die zweite folgt dem Kalender einer bestimmten Zeitzone. Ein Tag dauert nicht immer vierundzwanzig Stunden. Deshalb lassen sich beide Regeln nicht mit derselben Logik zum Addieren von Sekunden umsetzen.
Speichern Sie für eine tägliche Regel Stunde, Minute, Zeitzonenkennung und Version der angewendeten Strategie. Der absolute Zeitpunkt der nächsten Ausführung kann Abfragen erleichtern, ersetzt aber nicht die ursprüngliche Regel. Ändert der Nutzer die Zeitzone oder die Strategie, muss neu gerechnet werden.
Datestellt einen absoluten Zeitpunkt dar und enthält keine eigene Zeitzone. „Täglich um eine bestimmte Uhrzeit“ ist eine Kalenderregel, die mit einem ausdrücklich festgelegtenCalendarundTimeZoneinterpretiert werden muss.
Legen Sie außerdem fest, welche Zeitzone maßgeblich ist: die beim Anlegen der Regel festgelegte Zeitzone oder die des aktuellen Aufenthaltsorts des Nutzers. Überlassen Sie diese Produktentscheidung nicht der aktuellen Zeitzone des Cloud-Rechners. Speichern Sie auch nicht nur einen festen UTC-Offset, denn dieser kann künftige Zeitumstellungen nicht abbilden.
Fehlende und doppelte Ortszeiten als Produktregeln festlegen
Beim Vorstellen der Uhr im Frühjahr kann 02:30 Uhr ausfallen. Sie können den betreffenden Tag überspringen, die Ausführung auf die erste gültige Uhrzeit dieses Tages verschieben oder sie unter Beibehaltung des Minutenwerts nach hinten verlegen. Diese drei Varianten liefern unterschiedliche Ergebnisse.
Die Strategie .strict von Calendar verlangt eine exakte Übereinstimmung. Bei einer täglichen Regel wird bei einer nicht vorhandenen Uhrzeit an den folgenden Tagen weitergesucht. .nextTime wählt die nächste gültige Uhrzeit; dabei darf nicht vorausgesetzt werden, dass der ursprüngliche Minutenwert erhalten bleibt. Soll dieser beibehalten werden, müssen Sie .nextTimePreservingSmallerComponents gesondert prüfen.
Beim Zurückstellen der Uhr im Herbst kann 02:30 Uhr zweimal vorkommen. Wählen Sie mit .first oder .last ausdrücklich eines der beiden Vorkommen. Soll das Produkt beide ausführen, müssen zwei mögliche Zeitpunkte mit jeweils eigener Ereignisidentität vorgesehen werden. Ein einzelner Aufruf zur Suche nach einer passenden Uhrzeit ist dafür keine vollständige Implementierung.
Swift-Abnahmeskript mit festen Testdaten ausführen
Speichern Sie den folgenden Inhalt als recurrence.swift. Das Beispiel verwendet den gregorianischen Kalender und eine ausdrücklich festgelegte Zeitzone. Die Datumswerte sind feste Testfälle für Grenzsituationen, keine Messzeitpunkte. Weder muss die Rechneruhr verändert noch ein Simulator gestartet werden.
import Foundation
var calendar = Calendar(identifier: .gregorian)
calendar.timeZone = TimeZone(identifier: "Europe/Berlin")!
let formatter = ISO8601DateFormatter()
func instant(_ value: String) -> Date {
guard let date = formatter.date(from: value) else {
fatalError("Invalid fixture date")
}
return date
}
func next(
after cursor: Date,
policy: Calendar.MatchingPolicy,
repeated: Calendar.RepeatedTimePolicy
) -> Date {
guard let date = calendar.nextDate(
after: cursor,
matching: DateComponents(hour: 2, minute: 30, second: 0),
matchingPolicy: policy,
repeatedTimePolicy: repeated,
direction: .forward
) else {
fatalError("No matching occurrence")
}
precondition(date > cursor)
return date
}
let spring = instant("2027-03-28T00:00:00+01:00")
let skipped = next(
after: spring,
policy: .strict,
repeated: .first
)
precondition(skipped == instant("2027-03-29T02:30:00+01:00"))
let shifted = next(
after: spring,
policy: .nextTime,
repeated: .first
)
precondition(shifted == instant("2027-03-28T03:00:00+02:00"))
let autumn = instant("2027-10-31T00:00:00+02:00")
let first = next(
after: autumn,
policy: .strict,
repeated: .first
)
let last = next(
after: autumn,
policy: .strict,
repeated: .last
)
precondition(first == instant("2027-10-31T02:30:00+02:00"))
precondition(last == instant("2027-10-31T02:30:00+01:00"))
precondition(last.timeIntervalSince(first) == 3600)
Führen Sie das Skript mit der ausgewählten Entwicklungs-Toolchain aus:
xcrun swift recurrence.swift
Bei Erfolg beendet sich das Skript ohne Ausgabe; schlägt eine Assertion fehl, endet es mit einem Fehlerstatus. Lassen Sie diesen Fehler in die Pipeline einfließen, statt lediglich zu prüfen, ob Protokolle erzeugt wurden. Führen Sie die Testfälle nach einem Upgrade der Toolchain oder des Systems erneut aus und protokollieren Sie dabei Systemversion, Toolchain-Version und Zeitzonenkennung.
Das Skript prüft ausschließlich die feste Regel für 02:30 Uhr. Machen Sie Stunde und Minute bei der Integration ins Projekt zu Parametern und ergänzen Sie Testfälle für gewöhnliche Tage, Monatsenden, Jahresenden und den Schalttag. Halten Sie für jeden Testfall den erwarteten absoluten Zeitpunkt fest, statt nur formatierte Zeichenfolgen zu vergleichen.
Cursor-Fortschritt und doppelfreies Nachholen prüfen
Wenn Sie mehrere mögliche Ausführungszeitpunkte berechnen, verwenden Sie den zuletzt zurückgegebenen Wert als Cursor für die nächste Suche. Prüfen Sie dabei, dass die Ergebnisse streng monoton steigen. Ziehen Sie vor der nächsten Abfrage keine Sekunde ab: Bei einem exakten Grenztreffer könnte sonst dasselbe Ereignis erneut zurückgegeben werden. Begrenzen Sie bei stapelweiser Suche außerdem die Anzahl der Durchläufe, damit eine fehlerhafte Regel den Executor nicht über längere Zeit belegt.
Verwenden Sie zum Nachholen ein festes Zeitfenster: Der Anfang ist ausgeschlossen, das Ende eingeschlossen. Fixieren Sie zuerst den Endzeitpunkt und ermitteln Sie anschließend die möglichen Ausführungszeitpunkte. Lesen Sie nicht in jedem Schleifendurchlauf erneut die aktuelle Uhrzeit aus. Andernfalls erweitert eine lang laufende Aufgabe fortwährend den Nachholbereich, und die Abnahmeergebnisse lassen sich nicht reproduzieren.
Wenn eine Ausführung nur einmal täglich erfolgen soll, bilden Sie den Deduplizierungsschlüssel aus „Zeitplan-ID + Regelversion + lokalem Datum in der Zeitzone der Regel“. Abschlussdatensätze müssen dauerhaft gespeichert werden. Hat die Geschäftsoperation externe Nebenwirkungen, muss dieser Schlüssel auch an die Geschäftslogik übergeben werden. Eine reine Erfolgsmarkierung im Arbeitsspeicher reicht nicht aus.
Testen Sie eine Unterbrechung während der Verarbeitung: Führen Sie zunächst die Geschäftsoperation aus und simulieren Sie dann einen Abbruch, bevor der Abschlussdatensatz auf den Datenträger geschrieben wurde. Beim erneuten Versuch müssen die Idempotenzregeln der Geschäftslogik eine Wiederholung der Operation verhindern. Die Deduplizierung des Schedulers ist keine Transaktionsgarantie.
Kalenderberechnung und Systemausführung getrennt abnehmen
Wenn die reine Funktion die Tests bestanden hat, prüfen Sie im Simulator das Bearbeiten und Anzeigen der Regeln sowie das erneute Einlesen aus dem persistenten Speicher. Wann eine Ausführung im Hintergrund möglich ist, bestimmt das System; ein sekundengenauer Start lässt sich nicht zusichern. Zeigen Sie „geplanter Ausführungszeitpunkt“ und „tatsächlicher Ausführungszeitpunkt“ als getrennte Felder an, damit Verzögerungen bei der Fehlersuche nicht mit Kalenderfehlern verwechselt werden.
Prüfen Sie abschließend vier Punkte: Die Tests lesen nicht die Standardzeitzone aus; tägliche Regeln werden nicht um eine feste Sekundenzahl weitergeschaltet; die Strategie für doppelte Ortszeiten wird ausdrücklich übergeben; und das Nachholen verwendet ein stabiles Zeitfenster sowie dauerhaft gespeicherte Identitäten. Vergleichen Sie bei Regressionstests über Zeitumstellungen hinweg die berechneten Ergebnisse mit den Ausführungsdatensätzen, statt auf gut Glück die Systemuhr zu verstellen.
Häufig gestellte Fragen
Reicht es, für tägliche Aufgaben vierundzwanzig Stunden zu addieren?
Nur bei einem festen Zeitabstand. Soll die lokale Uhrzeit gleich bleiben, müssen die Uhrzeitkomponenten mit Calendar und einer expliziten Zeitzone abgeglichen werden.
Soll eine doppelt vorkommende Ortszeit zwei Ausführungen auslösen?
Die Produktregel muss das erste, das zweite oder beide Vorkommen wählen. Für genau eine tägliche Ausführung dienen Regelkennung, Revision und lokales Datum als Deduplizierungsschlüssel, nicht allein der UTC-Zeitstempel.
Führen Sie Ihre Projekte auf einem dedizierten physischen Mac aus
Erledigen Sie Builds, Tests und Remote-Desktop-Aufgaben auf einem Mac in der Cloud. Wählen Sie Ausstattung und Abrechnungszeitraum passend zu Ihrem Projekt. Den aktuellen Verfügbarkeitsstatus sehen Sie direkt in der Konsole.