Преобразовать Python UTC 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.32010-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+0400
В Python 2
2010-06-06 21:29:07.730000
2010-12-06 20:29:07.730000
2012-11-08 14:19:50.093911
pytz
2010-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, реализуя свои собственные часовые пояса. Но это было бы глупо.
Я кажется понял: вычисляет количество секунд с начала эпохи, затем переводит на местный timzeone через время.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. The преобразование наивный объект 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)