Преобразование строки 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 " и т. д. ?) Я уверен, что ответ на мой первый вопрос может содержать параметр отвечает второй.

937   10  

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

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