Python - От DST-коригирано местно време до UTC

Конкретна банка има клонове във всички големи градове по света. Всички те отварят в 10:00 сутринта местно време. Ако в рамките на часова зона, която използва лятно часово време, тогава, разбира се, местното време на отваряне също следва коригираното лятно време. И така, как да премина от местното време към UTC времето.

Това, от което се нуждая, е функция to_utc(localdt, tz) като тази:

Аргументи:

  • localdt: местно време, като наивен обект за дата и час, коригирано лятно време
  • tz: часова зона във формат TZ, напр. "Европа/Берлин"

Се завръща:

  • обект за дата и час, в UTC, съобразен с часовата зона

РЕДАКТИРАНЕ:

Най-голямото предизвикателство е да се установи дали местното време е в период с DST, което също означава, че е коригирано DST.

За „Европа/Берлин“, който има +1 лятно часово време през лятото:

  • 1 януари 10:00 => 1 януари 9:00 UTC
  • 1 юли 10:00 => 1 юли 8:00 UTC

За „Африка/Лагос“, който няма лятно часово време:

  • 1 януари 10:00 => 1 януари 9:00 UTC
  • 1 юли 10:00 => 1 юли 9:00 UTC

person Erik Ninn-Hansen    schedule 23.07.2011    source източник
comment
Клопка: 27 март 2011 г. в 01:00 часа, часовниците бяха преместени напред до 02:00 часа. Така че интервалът между 01:00 и 02:00 е невалиден. На 30 октомври 2011 г. в 01:00 часа часовниците ще бъдат върнати на 00:00 часа. Така че интервалът между 00:00 и 01:00 е двусмислен.   -  person Erik Ninn-Hansen    schedule 23.07.2011
comment
pytz описва, че преходите към DST не работят за никоя часова зона, която има такава. Ако пакет, създаден специално за помощ с часови зони, не поддържа това, тогава е твърде много работа за вас да свършите правилно сами. Ще трябва да се задоволите с почти правилно.   -  person agf    schedule 23.07.2011


Отговори (2)


Използвайки pytz и по-специално неговия метод за локализиране:

import pytz
import datetime as dt

def to_utc(localdt,tz):
    timezone=pytz.timezone(tz)
    utc=pytz.utc
    return timezone.localize(localdt).astimezone(utc)

if __name__=='__main__':
    for tz in ('Europe/Berlin','Africa/Lagos'):
        for date in (dt.datetime(2011,1,1,10,0,0),
                 dt.datetime(2011,7,1,10,0,0),
                 ):
            print('{tz:15} {l} --> {u}'.format(
                tz=tz,
                l=date.strftime('%b %d %H:%M'),
                u=to_utc(date,tz).strftime('%b %d %H:%M %Z')))

добиви

Europe/Berlin   Jan 01 10:00 --> Jan 01 09:00 UTC
Europe/Berlin   Jul 01 10:00 --> Jul 01 08:00 UTC
Africa/Lagos    Jan 01 10:00 --> Jan 01 09:00 UTC
Africa/Lagos    Jul 01 10:00 --> Jul 01 09:00 UTC
person unutbu    schedule 23.07.2011
comment
забележка: някои местни часове са двусмислени. Въпреки че е малко вероятно дадена банка да се отвори по време на прехода към DST; можете да използвате параметър is_dst=None за .localize(), за да потвърдите това. - person jfs; 03.10.2012

from datetime import datetime, tzinfo, timedelta

class GMT1(tzinfo):
    def utcoffset(self, dt):
        return timedelta(hours=1)
    def dst(self, dt):
        return timedelta(0)
    def tzname(self,dt):
        return "Europe/Prague"
year, month, day = 2011, 7, 23
dt = datetime(year, month, day, 10)

class UTC(tzinfo):
    def utcoffset(self, dt):
        return timedelta(0)
    def dst(self, dt):
        return timedelta(0)
    def tzname(self,dt):
        return "UTC"

def utc(localt, tz):
    return localt.replace(tzinfo=tz).astimezone(UTC())

print utc(dt, GMT1())

Нова версия. Това прави това, което искате - взема наивна дата, час и часова зона и връща UTC дата и час.

person agf    schedule 23.07.2011
comment
Вашето решение не успява да реши основното предизвикателство: Автоматична обработка на DST. - person Erik Ninn-Hansen; 23.07.2011
comment
Не съм сигурен, че разбирам. Ако tzinfo, който използвате, има timedelta за лятно часово време, то трябва да се обработва автоматично от utcnow()? - person agf; 23.07.2011
comment
Сега разбирам. Актуализирах отговора си. - person agf; 23.07.2011
comment
Все още не съм сигурен как това решава проблема с DST. Прага през юли трябва да бъде в UTC+2 (включително DST). Все още връщате timedelta(0) за dst в GMT1: правилно за GMT+1 наистина, но това не е часовата зона за Европа/Прага. - person Bruno; 11.01.2012