Как сделать незнакомый часовой пояс даты и времени в Python - PullRequest
411 голосов
/ 15 августа 2011

Что мне нужно сделать

У меня есть объект даты и времени, не зависящий от часового пояса, к которому мне нужно добавить часовой пояс, чтобы иметь возможность сравнивать его с другим часовым поясом.осведомленные объекты даты и времени.Я не хочу преобразовывать все мое приложение в часовой пояс, не подозревая об этом одном унаследованном случае.

Что я уже пробовал

Сначала, чтобы продемонстрировать проблему:

Python 2.6.1 (r261:67515, Jun 24 2010, 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
>>>

Не удивительно, что это не удалось, так как он на самом деле пытается выполнить преобразование.Замена кажется лучшим выбором (согласно Python: как получить значение datetime.today (), которое «учитывает часовой пояс»? ):

>>> unaware.replace(tzinfo=pytz.UTC)
datetime.datetime(2011, 8, 15, 8, 15, 12, tzinfo=<UTC>)
>>> unaware == aware
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: can't compare offset-naive and offset-aware datetimes
>>> 

Но как вы можетевидите, замена, кажется, устанавливает tzinfo, но не делает объект осведомленным.Я собираюсь вернуться к лечению входной строки, чтобы иметь часовой пояс перед его синтаксическим анализом (я использую dateutil для анализа, если это имеет значение), но это кажется невероятно глупым.

Кроме того, я 'мы пробовали это и в python 2.6, и в python 2.7 с одинаковыми результатами.

Context

Я пишу парсер для некоторых файлов данных.Существует старый формат, который мне нужно поддерживать, когда строка даты не имеет индикатора часового пояса.Я уже исправил источник данных, но мне все еще нужно поддерживать устаревший формат данных.Однократное преобразование устаревших данных не подходит по разным причинам бизнес-BS.Хотя в целом мне не нравится идея жесткого кодирования часового пояса по умолчанию, в этом случае он кажется наилучшим вариантом.Я с достаточной уверенностью знаю, что все унаследованные данные находятся в UTC, поэтому я готов принять на себя риск невыполнения этого требования в этом случае.

Ответы [ 9 ]

489 голосов
/ 15 августа 2011

В общем, для создания наивного часового пояса даты и времени используйте метод локализации :

import datetime
import pytz

unaware = datetime.datetime(2011, 8, 15, 8, 15, 12, 0)
aware = datetime.datetime(2011, 8, 15, 8, 15, 12, 0, pytz.UTC)

now_aware = pytz.utc.localize(unaware)
assert aware == now_aware

Для часового пояса UTC на самом деле нет необходимости использовать localizeтак как нет расчета летнего времени для обработки:

now_aware = unaware.replace(tzinfo=pytz.UTC)

работает.(.replace возвращает новое время и дату; оно не изменяет unaware.)

107 голосов
/ 13 января 2017

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

from datetime import datetime
from datetime import timezone

dt = datetime.now()
dt.replace(tzinfo=timezone.utc)

print(dt.replace(tzinfo=timezone.utc).isoformat())
'2017-01-12T22:11:31+00:00'

Меньше зависимостейи никаких проблем с pytz.

ПРИМЕЧАНИЕ: Если вы хотите использовать это с python3 и python2, вы можете использовать это также для импорта часового пояса (жестко запрограммировано для UTC):

try:
    from datetime import timezone
    utc = timezone.utc
except ImportError:
    #Hi there python2 user
    class UTC(tzinfo):
        def utcoffset(self, dt):
            return timedelta(0)
        def tzname(self, dt):
            return "UTC"
        def dst(self, dt):
            return timedelta(0)
    utc = UTC()
69 голосов
/ 22 ноября 2011

Я использовал от 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)

но ответ перед этим также является хорошим решением.

37 голосов
/ 27 января 2015

Я использую это утверждение в Django, чтобы преобразовать неосведомленное время в осведомленное:

from django.utils import timezone

dt_aware = timezone.make_aware(dt_unaware, timezone.get_current_timezone())
11 голосов
/ 30 марта 2017

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

Если бы вы просто выбрали имяможно было бы предположить, что метод replace () будет применим и даст правильный объект с указанием даты и времени.Это не тот случай.

замена (tzinfo = ...) кажется случайной в своем поведении .Поэтому бесполезно.Не используйте это!

localize - это правильная функция для использования.Пример:

localdatetime_aware = tz.localize(datetime_nonaware)

Или более полный пример:

import pytz
from datetime import datetime
pytz.timezone('Australia/Melbourne').localize(datetime.now())

дает мне значение даты / времени текущего времени по местному времени:

datetime.datetime(2017, 11, 3, 7, 44, 51, 908574, tzinfo=<DstTzInfo 'Australia/Melbourne' AEDT+11:00:00 DST>)
8 голосов
/ 15 января 2014

Это кодифицирует @ Sérgio и @ unutbu's ответы .Он будет «просто работать» с pytz.timezone объектом или строкой IANA Time Zone .

def make_tz_aware(dt, tz='UTC', is_dst=None):
    """Add timezone information to a datetime object, only if it is naive."""
    tz = dt.tzinfo or tz
    try:
        tz = pytz.timezone(tz)
    except AttributeError:
        pass
    return tz.localize(dt, is_dst=is_dst) 

Это похоже на datetime.localize() (или .inform() или .awarify()) должен делать, принимать как строки, так и объекты часового пояса для аргумента tz и по умолчанию UTC, если часовой пояс не указан.

3 голосов
/ 24 июня 2017

Для добавления местного часового пояса; (используя dateutil)

from dateutil import tz
import datetime

dt_unaware = datetime.datetime(2017, 6, 24, 12, 24, 36)

dt_aware = dt_unaware.replace(tzinfo=tz.tzlocal())
2 голосов
/ 22 августа 2017

два метода, которые я знаю чисто

from datetime import datetime
import pytz

naive = datetime.now()
aware = naive.replace(tzinfo=pytz.UTC)

или

aware = pytz.UTC.localize(naive)

Конечно, вы можете использовать любой часовой пояс вместо UTC,

0 голосов
/ 26 сентября 2016

в формате ответа unutbu;Я сделал служебный модуль, который обрабатывает подобные вещи, с более интуитивным синтаксисом.Может быть установлен с pip.

import datetime
import saturn

unaware = datetime.datetime(2011, 8, 15, 8, 15, 12, 0)
now_aware = saturn.fix_naive(unaware)

now_aware_madrid = saturn.fix_naive(unaware, 'Europe/Madrid')
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...