Преобразование строки UTC datetime в локальное datetime с помощью Python
мне никогда не приходилось конвертировать время в UTC и из него. Недавно был запрос, чтобы мое приложение было в курсе часового пояса, и я бегал по кругу. Много информации о преобразовании местного времени в UTC, которую я нашел довольно элементарно (возможно, я тоже делаю это неправильно), но я не могу найти никакой информации о легком преобразовании времени UTC в часовой пояс конечных пользователей.
в двух словах, и android-приложение отправляет мне (appengine app) данные и в этих данных является меткой времени. К храните эту метку времени в формате utc, который я использую:
datetime.utcfromtimestamp(timestamp)
это, кажется, работает. Когда мое приложение хранит данные, оно хранится как 5 часов вперед (я EST -5)
данные хранятся на BigTable appengine, и при извлечении он выходит в виде строки, как так:
"2011-01-21 02:37:21"
Как преобразовать эту строку в DateTime в правильном часовом поясе пользователя?
кроме того, каково рекомендуемое хранилище для информации о часовом поясе пользователей? (Как это сделать вы обычно храните информацию TZ ie:" -5: 00 "или" EST " и т. д. ?) Я уверен, что ответ на мой первый вопрос может содержать параметр отвечает второй.
10 ответов:
если вы не хотите предоставить свой собственный
tzinfoобъекты, проверить python-dateutil библиотека. Он обеспечиваетtzinfoреализации поверх a zoneinfo (Olson) database таким образом, что вы можете ссылаться на правила часового пояса по несколько каноническому имени.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)Edit расширенный пример, чтобы показать
strptimeиспользованиеEdit 2 исправлено использование API, чтобы показать лучший метод точки входа
изменить 3 включены методы автоматического обнаружения для часовых поясов (Yarin)
вот упругий метод, который не зависит от каких-либо внешних библиотек:
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
посмотреть 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
Если вы хотите получить правильный результат даже для времени, которое соответствует неоднозначному местному времени (например, во время перехода DST) и / или локальное смещение 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)
при использовании django, вы можете использовать часовой пояс.метод localtime (см. https://docs.djangoproject.com/en/dev/topics/i18n/timezones/).
from django.utils import timezone date # datetime.datetime(2014, 8, 1, 20, 15, 0, 513000, tzinfo=<UTC>) timezone.localtime(date) # datetime.datetime(2014, 8, 1, 16, 15, 0, 513000, tzinfo=<DstTzInfo 'America/New_York' EDT-1 day, 20:00:00 DST>)
этот ответ должен быть полезен, если вы не хотите использовать какие-либо другие модули, кроме
datetime.
datetime.utcfromtimestamp(timestamp)возвращает наивныйdatetimeобъект (не осознающий). Знающие-это знающие часовой пояс, а наивные-нет. Вы хотите знать, если вы хотите конвертировать между часовыми поясами (например, между UTC и местным временем).если вы не тот, кто создает экземпляр даты для начала, но вы все равно можете создать наивный
datetimeобъект в UTC времени, вы можете попробовать это Python 3.x код для его преобразования:import datetime d=datetime.datetime.strptime("2011-01-21 02:37:21", "%Y-%m-%d %H:%M:%S") #Get your naive datetime object d=d.replace(tzinfo=datetime.timezone.utc) #Convert it to an aware datetime object in UTC time. d=d.astimezone() #Convert it to your local timezone (still aware) print(d.strftime("%d %b %Y (%I:%M:%S:%f %p) %Z")) #Print it with a directive of choiceбудьте осторожны, чтобы не ошибочно предположить, что если ваш часовой пояс в настоящее время MDT, что переход на летнее время не работает с вышеуказанным кодом, так как он печатает MST. Вы заметите, что если вы измените месяц на август, он будет печатать MDT.
еще один простой способ, чтобы получить знать
Я традиционно откладываю это на frontend -- send times из бэкэнда в качестве временных меток или в каком-либо другом формате datetime в UTC, а затем позволяю клиенту определить смещение часового пояса и отобразить эти данные в соответствующем часовом поясе.
для веб-приложения это довольно легко сделать в javascript - вы можете легко вычислить смещение часового пояса браузера с помощью встроенных методов, а затем правильно отобразить данные из бэкэнда.
вот быстрая и грязная версия, которая использует настройки локальных систем для определения разницы во времени. Примечание: это не будет работать, если вам нужно преобразовать в часовой пояс, что ваша текущая система не работает. Я проверил это с настройками Великобритании в часовом поясе BST
from datetime import datetime def ConvertP4DateTimeToLocal(timestampValue): assert isinstance(timestampValue, int) # get the UTC time from the timestamp integer value. d = datetime.utcfromtimestamp( timestampValue ) # calculate time difference from utcnow and the local system time reported by OS offset = datetime.now() - datetime.utcnow() # Add offset to UTC time and return it return d + offset
можно использовать
calendar.timegmчтобы конвертировать ваше время в секундах с эпохи Unix иtime.localtimeпреобразовать обратно:import calendar import time time_tuple = time.strptime("2011-01-21 02:37:21", "%Y-%m-%d %H:%M:%S") t = calendar.timegm(time_tuple) print time.ctime(t)дает
Fri Jan 21 05:37:21 2011(потому что я нахожусь в часовом поясе UTC+03:00).
можно использовать стрелка
from datetime import datetime import arrow now = datetime.utcnow() print(arrow.get(now).to('local').format()) # '2018-04-04 15:59:24+02:00'вы можете кормить
arrow.get()С чем угодно. метка времени, строка iso и т. д.
Comments