Преобразовать в Python мирового datetime для местного типа datetime, используя только стандартную библиотеку Python?
У меня есть экземпляр python datetime, который был создан с помощью datetime.utcnow() и сохраняется в базе данных.
для отображения я хотел бы преобразовать экземпляр datetime, полученный из базы данных, в локальный datetime, используя локальный часовой пояс по умолчанию (т. е. как если бы datetime был создан с использованием datetime.теперь.))(
Как я могу преобразовать UTC datetime в локальное datetime, используя только стандартную библиотеку python (например, без зависимости pytz)?
кажется, один решение было бы использовать datetime.astimezone (tz ), но как бы вы получили локальный часовой пояс по умолчанию?
9 ответов:
В Python 3.3+:
from datetime import timezone def utc_to_local(utc_dt): return utc_dt.replace(tzinfo=timezone.utc).astimezone(tz=None)В Python 2/3:
import calendar from datetime import datetime, timedelta def utc_to_local(utc_dt): # get integer timestamp to avoid precision lost timestamp = calendar.timegm(utc_dt.timetuple()) local_dt = datetime.fromtimestamp(timestamp) assert utc_dt.resolution >= timedelta(microseconds=1) return local_dt.replace(microsecond=utc_dt.microsecond)используя
pytz(оба Python 2/3):import pytz local_tz = pytz.timezone('Europe/Moscow') # use your local timezone name here # NOTE: pytz.reference.LocalTimezone() would produce wrong result here ## You could use `tzlocal` module to get local timezone on Unix and Win32 # from tzlocal import get_localzone # $ pip install tzlocal # # get local timezone # local_tz = get_localzone() def utc_to_local(utc_dt): local_dt = utc_dt.replace(tzinfo=pytz.utc).astimezone(local_tz) return local_tz.normalize(local_dt) # .normalize might be unnecessaryпример
def aslocaltimestr(utc_dt): return utc_to_local(utc_dt).strftime('%Y-%m-%d %H:%M:%S.%f %Z%z') print(aslocaltimestr(datetime(2010, 6, 6, 17, 29, 7, 730000))) print(aslocaltimestr(datetime(2010, 12, 6, 17, 29, 7, 730000))) print(aslocaltimestr(datetime.utcnow()))выход
Python 3.3Python 22010-06-06 21:29:07.730000 MSD+0400 2010-12-06 20:29:07.730000 MSK+0300 2012-11-08 14:19:50.093745 MSK+0400pytz2010-06-06 21:29:07.730000 2010-12-06 20:29:07.730000 2012-11-08 14:19:50.0939112010-06-06 21:29:07.730000 MSD+0400 2010-12-06 20:29:07.730000 MSK+0300 2012-11-08 14:19:50.146917 MSK+0400Примечание: он учитывает DST и недавнее изменение смещения utc для часового пояса MSK.
Я не знаю, работают ли решения без pytz на Windows.
вы не можете сделать это с только стандартной библиотеки стандартная библиотека не имеет часовых поясов. Вам нужно pytz или dateutil.
>>> from datetime import datetime >>> now = datetime.utcnow() >>> from dateutil import tz >>> HERE = tz.tzlocal() >>> UTC = tz.gettz('UTC') The Conversion: >>> gmt = now.replace(tzinfo=UTC) >>> gmt.astimezone(HERE) datetime.datetime(2010, 12, 30, 15, 51, 22, 114668, tzinfo=tzlocal())или же, вы можете сделать это без pytz или dateutil, реализуя свои собственные часовые пояса. Но это было бы глупо.
Я думаю, что понял это: вычисляет количество секунд с момента эпохи, а затем преобразует в локальный часовой пояс, используя время.localtime, а затем преобразует структуру времени обратно в datetime...
EPOCH_DATETIME = datetime.datetime(1970,1,1) SECONDS_PER_DAY = 24*60*60 def utc_to_local_datetime( utc_datetime ): delta = utc_datetime - EPOCH_DATETIME utc_epoch = SECONDS_PER_DAY * delta.days + delta.seconds time_struct = time.localtime( utc_epoch ) dt_args = time_struct[:6] + (delta.microseconds,) return datetime.datetime( *dt_args )он правильно применяет летнее / зимнее DST:
>>> utc_to_local_datetime( datetime.datetime(2010, 6, 6, 17, 29, 7, 730000) ) datetime.datetime(2010, 6, 6, 19, 29, 7, 730000) >>> utc_to_local_datetime( datetime.datetime(2010, 12, 6, 17, 29, 7, 730000) ) datetime.datetime(2010, 12, 6, 18, 29, 7, 730000)
стандартная библиотека Python не поставляется с любым
tzinfoреализации вообще. Я всегда считал это удивительным недостатком модуля datetime.на документация для класса tzinfo есть некоторые полезные примеры. Найдите большой блок кода в конце раздела.
вы не можете сделать это с помощью стандартной библиотеки. Используя pytz модуль вы можете конвертировать любой наивный/осведомленный объект datetime в любой другой часовой пояс. Давайте посмотрим некоторые примеры использования Python 3.
наивный объекты, созданные с помощью метода класса
utcnow()преобразование наивный объект в любой другой часовой пояс, сначала вы должны преобразовать его в в курсе объекта datetime. Вы можете использовать
replaceметод конвертировании наивный datetime объект в в курсе объекта datetime. Затем преобразовать в курсе объект datetime для любого другого часового пояса, который вы можете использоватьastimezoneметод.переменная
pytz.all_timezonesдает вам список всех доступных часовых поясов в модуле pytz.import datetime,pytz dtobj1=datetime.datetime.utcnow() #utcnow class method print(dtobj1) dtobj3=dtobj1.replace(tzinfo=pytz.UTC) #replace method dtobj_hongkong=dtobj3.astimezone(pytz.timezone("Asia/Hong_Kong")) #astimezone method print(dtobj_hongkong)наивный объекты, созданные с помощью метода класса
now(), потому что
nowметод возвращает текущую дату и время, так что вы сначала нужно сделать часовой пояс объекта datetime. Элементlocalizeфункция преобразует a наивный объект datetime в объект datetime с поддержкой часового пояса. Тогда вы можете использоватьastimezoneметод, чтобы преобразовать его в другой часовой пояс.dtobj2=datetime.datetime.now() mytimezone=pytz.timezone("Europe/Vienna") #my current timezone dtobj4=mytimezone.localize(dtobj2) #localize function dtobj_hongkong=dtobj4.astimezone(pytz.timezone("Asia/Hong_Kong")) #astimezone method print(dtobj_hongkong)
основываясь на комментарии Алексея. Это должно работать и для DST.
import time import datetime def utc_to_local(dt): if time.localtime().tm_isdst: return dt - datetime.timedelta(seconds = time.altzone) else: return dt - datetime.timedelta(seconds = time.timezone)
простой (но, возможно, ошибочный) способ, который работает в Python 2 и 3:
import time import datetime def utc_to_local(dt): return dt - datetime.timedelta(seconds = time.timezone)его преимущество заключается в том, что тривиально писать обратную функцию
самый простой способ, который я нашел, это получить смещение времени where вы, затем вычесть из часа.
def format_time(ts,offset): if not ts.hour >= offset: ts = ts.replace(day=ts.day-1) ts = ts.replace(hour=ts.hour-offset) else: ts = ts.replace(hour=ts.hour-offset) return tsэто работает для меня в Python 3.5.2.
вот еще один способ изменить часовой пояс в формате datetime (я знаю, что потратил свою энергию на это, но я не видел эту страницу, поэтому я не знаю, как) без min. и сек. потому что мне это не нужно для моего проекта:
def change_time_zone(year, month, day, hour): hour = hour + 7 #<-- difference if hour >= 24: difference = hour - 24 hour = difference day += 1 long_months = [1, 3, 5, 7, 8, 10, 12] short_months = [4, 6, 9, 11] if month in short_months: if day >= 30: day = 1 month += 1 if month > 12: year += 1 elif month in long_months: if day >= 31: day = 1 month += 1 if month > 12: year += 1 elif month == 2: leap_years = [2000, 2004, 2008, 2012, 2016, 2020, 2024, 2028, 2032, 2036, 2040, 2044, 2048] if year in leap_years: if day >= 29: day = 1 month += 1 if month > 12: year += 1 elif year not in leap_years: if day >= 28: day = 1 month += 1 if month > 12: year += 1 return datetime(int(year), int(month), int(day), int(hour), 00)
Comments