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
- Otwieranie i zamykanie Terminala na Macu — Apple
- Korzystanie z Pythona w systemie macOS — Python Software Foundation
- datetime — podstawowe typy daty i czasu — Python Software Foundation
- zoneinfo — obsługa stref czasowych IANA — Python Software Foundation
- PEP 495 – rozstrzyganie niejednoznaczności czasu lokalnego — Python Software Foundation
- PEP 615 – obsługa bazy stref czasowych IANA w bibliotece standardowej — Python Software Foundation
- RFC 3339: Data i czas w Internecie: znaczniki czasu — RFC Editor
- RFC 9557: Data i czas w Internecie: znaczniki czasu z dodatkowymi informacjami — RFC Editor