Вопрос-Ответ

Convert UTC datetime string to local datetime

Преобразование строки UTC datetime в локальное datetime

Мне никогда не приходилось преобразовывать время в UTC и обратно. Недавно поступил запрос на то, чтобы мое приложение учитывало часовой пояс, и я бегал по кругу. Много информации о преобразовании местного времени в UTC, которое я нашел довольно элементарным (возможно, я и это делаю неправильно), но я не могу найти никакой информации о том, как легко преобразовать время UTC в часовой пояс конечного пользователя.

В двух словах, и приложение Android отправляет мне (приложение appengine) данные, а внутри этих данных находится временная метка. Чтобы сохранить эту временную метку в соответствии со временем utc, я использую:

datetime.utcfromtimestamp(timestamp)

Кажется, это работает. Когда мое приложение сохраняет данные, они сохраняются на 5 часов вперед (у меня EST -5)

Данные хранятся в BigTable appengine, и при извлечении они выдаются в виде строки, подобной следующей:

"2011-01-21 02:37:21"

Как мне преобразовать эту строку в дату и время в правильном часовом поясе пользователя?

Кроме того, каково рекомендуемое хранилище для информации о часовом поясе пользователя? (Как вы обычно храните информацию о времени, например: "-5: 00" или "EST" и т.д. и т.п.?) Я уверен, что ответ на мой первый вопрос может содержать параметр, который отвечает на второй.

Переведено автоматически
Ответ 1

Если вы не хотите предоставлять свои собственные tzinfo объекты, ознакомьтесь с библиотекой python-dateutil. Он предоставляет tzinfo реализации поверх базы данных zoneinfo (Olson), так что вы можете ссылаться на правила часовых поясов с помощью несколько канонического имени.

from datetime import datetime
from dateutil import tz

# METHOD 1: Hardcode zones:
from_zone = tz.gettz('UTC')
to_zone = tz.gettz('America/New_York')

# METHOD 2: Auto-detect zones:
from_zone = tz.tzutc()
to_zone = tz.tzlocal()

# utc = datetime.utcnow()
utc = datetime.strptime('2011-01-21 02:37:21', '%Y-%m-%d %H:%M:%S')

# Tell the datetime object that it's in UTC time zone since
# datetime objects are 'naive' by default
utc = utc.replace(tzinfo=from_zone)

# Convert time zone
central = utc.astimezone(to_zone)

Отредактируйте расширенный пример, чтобы показать strptime использование

Правка 2 Исправлено использование API для отображения лучшего метода точки входа

Правка 3 Включены методы автоматического определения часовых поясов (Yarin)

Ответ 2

Вот надежный метод, который не зависит ни от каких внешних библиотек:

from datetime import datetime
import time

def datetime_from_utc_to_local(utc_datetime):
now_timestamp = time.time()
offset = datetime.fromtimestamp(now_timestamp) - datetime.utcfromtimestamp(now_timestamp)
return utc_datetime + offset

Это позволяет избежать проблем с синхронизацией в примере DelboyJay. И меньших проблем с синхронизацией в поправке Эрика ван Остена.

В качестве интересной сноски, вычисленное выше смещение часового пояса может отличаться от следующего, казалось бы, эквивалентного выражения, вероятно, из-за изменений в правилах перехода на летнее время:

offset = datetime.fromtimestamp(0) - datetime.utcfromtimestamp(0) # NO!

Обновление: Недостатком этого фрагмента является использование смещения UTC текущего времени, которое может отличаться от смещения UTC входного datetime . Другое решение смотрите в комментариях к этому ответу.

Чтобы обойти различия во времени, возьмите время эпохи из прошедшего времени. Вот что я делаю:

def utc2local(utc):
epoch = time.mktime(utc.timetuple())
offset = datetime.fromtimestamp(epoch) - datetime.utcfromtimestamp(epoch)
return utc + offset
Ответ 3

Смотрите документацию по datetime по объектам tzinfo. Вы должны реализовать часовые пояса, которые хотите поддерживать самостоятельно. Примеры приведены в нижней части документации.

Вот простой пример:

from datetime import datetime,tzinfo,timedelta

class Zone(tzinfo):
def __init__(self,offset,isdst,name):
self.offset = offset
self.isdst = isdst
self.name = name
def utcoffset(self, dt):
return timedelta(hours=self.offset) + self.dst(dt)
def dst(self, dt):
return timedelta(hours=1) if self.isdst else timedelta(0)
def tzname(self,dt):
return self.name

GMT = Zone(0,False,'GMT')
EST = Zone(-5,False,'EST')

print datetime.utcnow().strftime('%m/%d/%Y %H:%M:%S %Z')
print datetime.now(GMT).strftime('%m/%d/%Y %H:%M:%S %Z')
print datetime.now(EST).strftime('%m/%d/%Y %H:%M:%S %Z')

t = datetime.strptime('2011-01-21 02:37:21','%Y-%m-%d %H:%M:%S')
t = t.replace(tzinfo=GMT)
print t
print t.astimezone(EST)

Вывод

01/22/2011 21:52:09 
01/22/2011 21:52:09 GMT
01/22/2011 16:52:09 EST
2011-01-21 02:37:21+00:00
2011-01-20 21:37:21-05:00a
Ответ 4

Если вы хотите получить правильный результат даже для времени, соответствующего неоднозначному местному времени (например, при переходе на летнее время), и / или локальное смещение utc отличается в разное время в вашем местном часовом поясе, тогда используйте pytz часовые пояса:

#!/usr/bin/env python
from datetime import datetime
import pytz # $ pip install pytz
import tzlocal # $ pip install tzlocal

local_timezone = tzlocal.get_localzone() # get pytz tzinfo
utc_time = datetime.strptime("2011-01-21 02:37:21", "%Y-%m-%d %H:%M:%S")
local_time = utc_time.replace(tzinfo=pytz.utc).astimezone(local_timezone)
python datetime