Преобразовать в Python мирового datetime для местного типа datetime, используя только стандартную библиотеку Python?



У меня есть экземпляр python datetime, который был создан с помощью datetime.utcnow() и сохраняется в базе данных.



для отображения я хотел бы преобразовать экземпляр datetime, полученный из базы данных, в локальный datetime, используя локальный часовой пояс по умолчанию (т. е. как если бы datetime был создан с использованием datetime.теперь.))(



Как я могу преобразовать UTC datetime в локальное datetime, используя только стандартную библиотеку python (например, без зависимости pytz)?



кажется, один решение было бы использовать datetime.astimezone (tz ), но как бы вы получили локальный часовой пояс по умолчанию?

833   9  

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.3
2010-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, реализуя свои собственные часовые пояса. Но это было бы глупо.

Я думаю, что понял это: вычисляет количество секунд с момента эпохи, а затем преобразует в локальный часовой пояс, используя время.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

    Ничего не найдено.