Как сделать объект datetime осведомленным (не наивным)
Что мне нужно сделать
У меня есть объект datetime, не зависящий от часового пояса, к которому мне нужно добавить часовой пояс, чтобы иметь возможность сравнивать его с другими объектами datetime, зависящими от часового пояса. Я не хочу, чтобы все мое приложение не знало о часовом поясе для этого единственного устаревшего случая.
Что я пробовал
Сначала, чтобы продемонстрировать проблему:
Python 2.6.1 (r261:67515, Jun 242010, 21:47:49) [GCC 4.2.1 (Apple Inc. build 5646)] on darwin Type"help", "copyright", "credits"or"license"for more information. >>> import datetime >>> import pytz >>> unaware = datetime.datetime(2011,8,15,8,15,12,0) >>> unaware datetime.datetime(2011, 8, 15, 8, 15, 12) >>> aware = datetime.datetime(2011,8,15,8,15,12,0,pytz.UTC) >>> aware datetime.datetime(2011, 8, 15, 8, 15, 12, tzinfo=<UTC>) >>> aware == unaware Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: can't compare offset-naive and offset-aware datetimes
Сначала я попробовал astimezone:
>>> unaware.astimezone(pytz.UTC) Traceback (most recent call last): File "<stdin>", line 1, in <module> ValueError: astimezone() cannot be applied to a naive datetime >>>
Но, как вы можете видеть, replace, похоже, устанавливает tzinfo, но не делает объект осведомленным. Я готов вернуться к обработке входной строки, чтобы у нее был часовой пояс перед ее анализом (я использую dateutil для синтаксического анализа, если это имеет значение), но это кажется невероятно запутанным.
Кроме того, я пробовал это как в Python 2.6, так и в Python 2.7, с теми же результатами.
Контекст
Я пишу анализатор для некоторых файлов данных. Мне нужно поддерживать старый формат, в котором строка даты не имеет индикатора часового пояса. Я уже исправил источник данных, но мне все еще нужно поддерживать устаревший формат данных. Одноразовое преобразование устаревших данных невозможно по различным причинам бизнес-стандарта. Хотя в целом мне не нравится идея жесткого кодирования часового пояса по умолчанию, в данном случае это кажется лучшим вариантом. Я с достаточной уверенностью знаю, что все устаревшие данные, о которых идет речь, находятся в UTC, поэтому я готов принять риск нарушения этого по умолчанию в данном случае.
Переведено автоматически
Ответ 1
В общем, чтобы сделать наивный объект datetime ориентированным на часовой пояс, используйте метод localize:
Для часового пояса UTC на самом деле нет необходимости использовать localize поскольку нет необходимости обрабатывать расчет перехода на летнее время:
now_aware = unaware.replace(tzinfo=pytz.UTC)
работает. (.replace возвращает новое datetime; оно не изменяется unaware.)
Ответ 2
Во всех этих примерах используется внешний модуль, но вы можете достичь того же результата, используя только модуль datetime, как также представлено в этом ответе SO:
ПРИМЕЧАНИЕ: Если вы хотите использовать это с python3 и python2, вы также можете использовать это для импорта часового пояса (жестко заданного для UTC):
try: from datetime import timezone utc = timezone.utc except ImportError: #Hi there python2 user classUTC(tzinfo): defutcoffset(self, dt): return timedelta(0) deftzname(self, dt): return"UTC" defdst(self, dt): return timedelta(0) utc = UTC()
Ответ 3
Я написал этот скрипт на Python 2 в 2011 году, но никогда не проверял, работает ли он на Python 3.
Я перешел с dt_aware на dt_unaware:
dt_unaware = dt_aware.replace(tzinfo=None)
и dt_unware в dt_aware:
from pytz import timezone localtz = timezone('Europe/Lisbon') dt_aware = localtz.localize(dt_unware)
Ответ 4
Python 3.9 добавляет zoneinfo модуль, так что теперь нужна только стандартная библиотека!
from zoneinfo import ZoneInfo from datetime import datetime unaware = datetime(2020, 10, 31, 12)