Aby przekształcić datę publikacji i nazwaną strefę czasową w dokładny moment północy, ustal lokalne 00:00:00 zgodnie z regułami tej strefy, sprawdź, czy taka godzina istnieje, a następnie przelicz ją na UTC. Ten proces w Terminalu na Macu wykrywa również powtórzone północe.

Załóżmy, że syntetyczny rekord publikacji zawiera datę 2025-07-15 i strefę America/New_York. Twoim zadaniem jest obliczyć znacznik czasu odpowiadający północy na początku tej daty. Poniższy proces tworzy znacznik czasu, który można skopiować do narzędzia przyjmującego UTC, a jednocześnie zachowuje pierwotną datę i strefę, by można było je sprawdzić.

Jakie informacje określają moment północy?

Podczas całego obliczenia rozdzielaj te cztery wartości:

Wartość Syntetyczny przykład Znaczenie
Data kalendarzowa 2025-07-15 Data w kalendarzu gregoriańskim bez godziny i strefy
Lokalna data i godzina 2025-07-15T00:00:00 Żądany odczyt zegara ściennego
Nazwana strefa czasowa America/New_York Reguły używane do interpretacji lokalnego odczytu
Ustalony moment 2025-07-15T04:00:00Z Konkretny moment wyrażony w UTC

Python reprezentuje datę kalendarzową za pomocą date, łączy pola daty i godziny za pomocą datetime, a do interpretacji świadomego strefy obiektu datetime używa informacji o strefie czasowej. Klasa timezone reprezentuje stałe przesunięcia, a zoneinfo udostępnia reguły nazwanych stref. Zobacz oficjalną dokumentację datetime i dokumentację zoneinfo.

Przesunięcie, takie jak -04:00, to różnica między czasem lokalnym a UTC dla danego odczytu. Nazwana strefa zawiera reguły, które mogą skutkować różnymi przesunięciami w różnych dniach. RFC 9557 wyjaśnia, dlaczego zastąpienie nazwanej strefy stałym przesunięciem może prowadzić do błędnych dalszych obliczeń. Zachowaj nazwę strefy zamiast kopiować przesunięcie z innego rekordu publikacji. RFC 9557: Data i czas w Internecie: znaczniki czasu z dodatkowymi informacjami

Na potrzeby tego zadania „północ” oznacza dokładnie 00:00:00 na początku podanej daty. Określ to wymaganie przed rozpoczęciem obliczeń: żądanie pierwszego prawidłowego momentu dnia kalendarzowego wymaga innej reguły, gdy północ nie występuje.

Dlaczego przed konwersją trzeba sprawdzić północ?

Zmiany czasu lokalnego mogą tworzyć lukę, w której dany odczyt zegara ściennego nie występuje, lub powtórzenie, w którym występuje dwukrotnie. PEP 495 w Pythonie definiuje te przypadki i udostępnia atrybut fold do rozróżniania powtórzonych odczytów. Dokumentuje też, że konstruktory i replace() nie odrzucają automatycznie nieistniejących lokalnych godzin. Samo przypisanie strefy nie weryfikuje więc żądanej północy. PEP 495 – rozstrzyganie niejednoznaczności czasu lokalnego

W przypadku wymogu dokładnej północy w publikacji zastosuj następującą regułę decyzyjną:

Liczba znalezionych prawidłowych momentów północy Interpretacja Działanie
Jeden Północ jest jednoznaczna Zwróć ten moment
Dwa Północ się powtarza Odrzuć, dopóki nie zostanie wybrana reguła wcześniejszego lub późniejszego wystąpienia
Zero Dokładna północ nie występuje Zgłoś, że dla tych danych wejściowych nie można spełnić wymagania

Poniższy program realizuje tę regułę, próbując obu wartości fold, przeliczając każdy kandydat na UTC, a następnie z powrotem na nazwaną strefę. Kandydat zostaje zaakceptowany tylko wtedy, gdy zwrócone lokalne pola dokładnie odpowiadają żądanej północy. Zduplikowane wyniki UTC są łączone w jeden kandydat. Ta sekwencja walidacji wynika z udokumentowanego sposobu konwersji i obsługi fold; stanowi dodatkową logikę aplikacji. datetime.astimezone(), PEP 495

Jak uruchomić obliczenie w Terminalu na Macu?

Otwórz Spotlight, wpisz Terminal i uruchom aplikację. Możesz też otworzyć w Finderze folder /Applications/Utilities i kliknąć dwukrotnie Terminal. Są to opisane przez Apple sposoby otwierania okna poleceń. Otwieranie i zamykanie Terminala na Macu

Uruchom poniższe polecenie, aby sprawdzić wersję Pythona:

python3 --version

Ten przykład wymaga Pythona 3.9 lub nowszego, w którym udostępniono zoneinfo. Jeśli Python nie jest zainstalowany albo jest starszy, skorzystaj z oficjalnego przewodnika instalacji na macOS, pobierz aktualnie obsługiwany instalator Pythona ze strony Python.org, a następnie ponownie sprawdź wersję. Proces wykorzystuje moduły biblioteki standardowej. zoneinfo — obsługa stref czasowych IANA, Korzystanie z Pythona w systemie macOS

Skopiuj cały poniższy blok do Terminala i naciśnij Return. To kompletne polecenie zawierające program w Pythonie. Aby obliczyć inny znacznik czasu publikacji, przed wklejeniem zmień DATE_TEXT i ZONE_NAME. Pozostaw REPEATED jako reject, chyba że świadomie wybierzesz regułę obsługi powtórzonej północy.

python3 - <<'PY'
from datetime import date, datetime, time, timezone
from zoneinfo import ZoneInfo, ZoneInfoNotFoundError

DATE_TEXT = '2025-07-15'
ZONE_NAME = 'America/New_York'
REPEATED = 'reject'  # 'reject', 'earlier', or 'later'


def resolve_midnight(date_text, zone_name, repeated='reject'):
    if repeated not in {'reject', 'earlier', 'later'}:
        raise ValueError('Repeated-time policy must be reject, earlier, or later.')

    day = date.fromisoformat(date_text)
    if day.isoformat() != date_text:
        raise ValueError('Use a date in YYYY-MM-DD format.')

    zone = ZoneInfo(zone_name)
    wall = datetime.combine(day, time.min)
    candidates = set()

    for fold in (0, 1):
        guess = wall.replace(tzinfo=zone, fold=fold)
        instant = guess.astimezone(timezone.utc)
        back = instant.astimezone(zone)
        if back.replace(tzinfo=None) == wall:
            candidates.add(instant)

    ordered = sorted(candidates)
    if not ordered:
        raise ValueError('Exact midnight does not exist on this date in this zone.')

    if len(ordered) == 2 and repeated == 'reject':
        choices = ', '.join(x.isoformat() for x in ordered)
        raise ValueError(
            'Midnight repeats. Choose earlier or later. UTC choices: ' + choices
        )

    chosen = ordered[-1] if repeated == 'later' else ordered[0]
    return chosen.astimezone(zone), chosen


try:
    local, utc = resolve_midnight(DATE_TEXT, ZONE_NAME, REPEATED)
except ZoneInfoNotFoundError:
    raise SystemExit(
        'Zone not found. Check the IANA name and time zone data installation.'
    )
except (ValueError, OverflowError) as exc:
    raise SystemExit(str(exc))

print('Civil date:', DATE_TEXT)
print('Named zone:', ZONE_NAME)
print('Local midnight:', local.isoformat())
print('UTC instant:', utc.isoformat().replace('+00:00', 'Z'))
PY

Dla podanego przykładu wynik wygląda następująco:

Data kalendarzowa: 2025-07-15
Nazwana strefa: America/New_York
Lokalna północ: 2025-07-15T00:00:00-04:00
Moment UTC: 2025-07-15T04:00:00Z

Czytaj te dwa wiersze ze znacznikami czasu łącznie. Wiersz lokalny potwierdza, że żądana godzina na zegarze ściennym to północ. Wiersz UTC wskazuje ten sam moment: odjęcie lokalnego przesunięcia wynoszącego minus cztery godziny daje 04:00:00 UTC. RFC 3339 definiuje znacznik czasu jako datę, godzinę i przesunięcie liczbowe albo Z. RFC 3339: Data i czas w Internecie: znaczniki czasu

Jak sprawdzić zwykłe i nietypowe wyniki?

Poniższe dane to syntetyczne przykłady publikacji wybrane w celu sprawdzenia działania programu. Ich wyniki obliczono za pomocą powyższego mechanizmu rozstrzygania i dostępnej bazy stref czasowych; nie są to rzeczywiste rekordy publikacji. Zmień dwie wartości wejściowe i ponownie uruchom całe polecenie dla każdego przypadku.

Data Nazwana strefa Wynik mechanizmu rozstrzygania
2025-01-15 America/New_York Jeden moment: 2025-01-15T05:00:00Z
2025-07-15 America/New_York Jeden moment: 2025-07-15T04:00:00Z
2018-11-04 America/Sao_Paulo Dokładna północ nie występuje; odrzuca
2020-11-01 America/Havana Północ się powtarza; domyślnie odrzuca
2011-12-30 Pacific/Apia Dokładna północ nie występuje; odrzuca

Pierwsze dwa wiersze pokazują, dlaczego data musi być uwzględniona w obliczeniu: ta sama nazwana strefa ustala północ na różne godziny UTC. W przypadku przykładu powtórzonej północy w Hawanie ustawienie REPEATED = 'earlier' wybiera 2020-11-01T04:00:00Z, a ustawienie later wybiera 2020-11-01T05:00:00Z. Nazwy odnoszą się do kolejności chronologicznej na osi czasu UTC.

Wynik informujący o braku północy wymaga decyzji dotyczącej wymagań publikacji. Jeśli dokładna północ jest niezbędna, jawnie wybierz inną datę lub strefę. Jeśli wymagany jest pierwszy prawidłowy czas w danym dniu, osobno zdefiniuj i zaimplementuj tę operację, uwzględniając również sposób postępowania w przypadku braku całego dnia. Ten mechanizm celowo zgłasza błąd zamiast po cichu podstawiać inną lokalną godzinę.

Co zrobić, gdy dane wejściowe powodują błąd?

W przypadku błędu daty podaj prawidłową datę gregoriańską w formacie YYYY-MM-DD, na przykład 2025-07-15. Program sprawdza zarówno poprawność kalendarzową, jak i zgodność z tym dokładnym formatem. Dane takie jak 2025-02-30 powodują błąd zamiast przejścia do kolejnego miesiąca.

W przypadku komunikatu Zone not found sprawdź pełny identyfikator IANA, w tym pisownię i wielkość liter. Python informuje, że ten wyjątek może oznaczać nieprawidłowy klucz albo brak danych stref czasowych. Standardowe wyszukiwanie najpierw korzysta z danych systemowych, a następnie z pakietu tzdata jako rozwiązania zapasowego. Jeśli brakuje danych, zainstaluj ten pakiet w używanym środowisku Pythona, a następnie ponownie uruchom mechanizm rozstrzygania. PEP 615 – obsługa bazy stref czasowych IANA w bibliotece standardowej

Zachowaj w notatkach roboczych pierwotną datę, nazwę strefy, wybór dotyczący powtórzonej godziny i ustalony znacznik czasu UTC. Jeśli wyniki obliczeń różnią się między komputerami, porównaj źródła ich danych o strefach czasowych. Instalacja pakietu zapasowego nie zastępuje automatycznie danych systemowych, które Python już znajduje. Źródła danych zoneinfo

Którą wartość skopiować do innego narzędzia?

Jeśli narzędzie docelowe przyjmuje znacznik czasu UTC, skopiuj wartość Moment UTC wraz z jej Z. Przed wprowadzeniem sprawdź udokumentowany format wejściowy narzędzia. Zwykłe pole daty nie zachowuje wszystkich informacji zawartych w ustalonym znaczniku czasu; jeśli chcesz zachować zamiar dotyczący harmonogramu, przechowuj obok niego pierwotną datę i nazwaną strefę.

RFC 9557 definiuje rozszerzony format znacznika czasu, który może zawierać przyrostek z nazwą strefy, ale format ten nadal przedstawia ustalony moment. Dokument uwzględnia też, że aktualizacje danych stref mogą powodować niespójności między zapisanymi przesunięciami a informacjami o strefie. Korzystaj z rozszerzonego zapisu tylko wtedy, gdy narzędzie docelowe deklaruje jego obsługę. RFC 9557, zakres i niespójne przesunięcia

Na koniec sprawdź, czy lokalny wynik pokazuje zamierzoną datę o godzinie 00:00:00, czy nazwana strefa jest zgodna z danymi wejściowymi oraz czy wybór dotyczący powtórzonej północy był świadomy. Po tych kontrolach wynik UTC jest ustalonym momentem północy zgodnie z regułami użytymi w obliczeniu.

Źródła