Преобразование даты с учетом часового пояса в местное время в Python - PullRequest
36 голосов
/ 28 марта 2011

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

В моем конкретном приложении используется Django (хотя на самом деле это общий вопрос по Python):

import iso8601

....

date_str="2010-10-30T17:21:12Z"

....

d = iso8601.parse_date(date_str)

foo = app.models.FooModel(the_date=d)
foo.save()

Это заставляет Django выдать ошибку:

raise ValueError("MySQL backend does not support timezone-aware datetimes.")

Что мне нужно, это:

d = iso8601.parse_date(date_str)
local_d = SOME_FUNCTION(d)
foo = app.models.FooModel(the_date=local_d)

Что бы SOME_FUNCTION было бы?

Ответы [ 4 ]

61 голосов
/ 17 августа 2012

В последних версиях Django (как минимум 1.4.1):

from django.utils.timezone import localtime

result = localtime(some_time_object)
58 голосов
/ 28 марта 2011

В общем, чтобы преобразовать произвольную дату / время с учетом часового пояса в наивную (локальную) дату и время, я бы использовал модуль pytz и astimezone для преобразования в местное время, а replace, чтобы сделать дату / время наивным :

In [76]: import pytz

In [77]: est=pytz.timezone('US/Eastern')

In [78]: d.astimezone(est)
Out[78]: datetime.datetime(2010, 10, 30, 13, 21, 12, tzinfo=<DstTzInfo 'US/Eastern' EDT-1 day, 20:00:00 DST>)

In [79]: d.astimezone(est).replace(tzinfo=None)
Out[79]: datetime.datetime(2010, 10, 30, 13, 21, 12)

Но так как ваша конкретная дата и время, похоже, находятся в часовом поясе UTC, вы можете сделать это вместо этого:

In [65]: d
Out[65]: datetime.datetime(2010, 10, 30, 17, 21, 12, tzinfo=tzutc())

In [66]: import datetime

In [67]: import calendar

In [68]: datetime.datetime.fromtimestamp(calendar.timegm(d.timetuple()))
Out[68]: datetime.datetime(2010, 10, 30, 13, 21, 12)

Кстати, вам может быть лучше хранить даты-даты как наивные даты UTC вместо наивных локальных дат-времени. Таким образом, ваши данные не зависят от местного времени, и вы конвертируете их в местное время или любой другой часовой пояс только в случае необходимости. В некотором роде аналогичен максимально возможной работе в Юникоде и кодированию только при необходимости.

Так что, если вы согласны с тем, что хранение даты и времени в наивном UTC является лучшим способом, тогда все, что вам нужно сделать, это определить:

local_d = d.replace(tzinfo=None)
2 голосов
/ 23 августа 2015

Переносное надежное решение должно использовать базу данных tz.Чтобы получить местный часовой пояс как pytz tzinfo объект, используйте tzlocal module :

#!/usr/bin/env python
import iso8601
import tzlocal # $ pip install tzlocal

local_timezone = tzlocal.get_localzone()
aware_dt = iso8601.parse_date("2010-10-30T17:21:12Z") # some aware datetime object
naive_local_dt = aware_dt.astimezone(local_timezone).replace(tzinfo=None)

Примечание: может быть заманчиво использовать что-то вроде:

#!/usr/bin/env python3
# ...
naive_local_dt = aware_dt.astimezone().replace(tzinfo=None)

, но может произойти сбой, если локальный часовой пояс имеет переменное смещение utc, но python не использует базу данных исторических часовых поясов на данной платформе.

0 голосов
/ 29 сентября 2015

Используя python-dateutil, вы можете анализировать дату в формате iso-8561 с помощью dateutil.parsrser.parse(), что даст вам datetime в часовом поясе UTC / Зулу.

Используя .astimezone(), вы можете преобразовать его в определенное время в другом часовом поясе.

Использование .replace(tzinfo=None) преобразует известное время в наивное время.

from datetime import datetime
from dateutil import parser as datetime_parser
from dateutil.tz import tzutc,gettz

aware = datetime_parser.parse('2015-05-20T19:51:35.998931Z').astimezone(gettz("CET"))
naive = aware.replace(tzinfo=None)

В общем, лучшая идея - преобразовать все даты в UTC, сохранить их таким образом и при необходимости преобразовать их обратно в локальные. Я использую aware.astimezone(tzutc()).replace(tzinfo=None), чтобы убедиться, что в UTC и конвертировать в наивный.

...