Почему datetime.datetime.utcnow() не содержит информацию о часовом поясе?

datetime.datetime.utcnow()

Почему этот datetime не имеет информации о часовом поясе, учитывая, что это явно UTC datetime?

Я бы ожидал, что это будет содержать tzinfo.

Ответ 1

Это означает, что это временная зона наивная, поэтому вы не можете использовать ее с помощью datetime.astimezone

вы можете дать ему часовой пояс, как это

import pytz  # 3rd party: $ pip install pytz

u = datetime.utcnow()
u = u.replace(tzinfo=pytz.utc) #NOTE: it works only with a fixed utc offset

теперь вы можете изменять часовые пояса

print(u.astimezone(pytz.timezone("America/New_York")))

Чтобы получить текущее время в заданном часовом поясе, вы можете напрямую передать tzinfo на datetime.now():

#!/usr/bin/env python
from datetime import datetime
import pytz # $ pip install pytz

print(datetime.now(pytz.timezone("America/New_York")))

Он работает для любого часового пояса, в том числе тех, которые наблюдают летнее время (DST), то есть оно работает для часовых поясов, которые могут иметь разные смещения utc в разное время (нефиксированное смещение utc). Не используйте tz.localize(datetime.now()) - он может завершиться неудачно во время перехода на конец DST, когда локальное время неоднозначно.

Ответ 2

Стандартные библиотеки Python не включают в себя классы tzinfo (но см. pep 431). Я могу только догадываться о причинах. Лично я думаю, что было ошибкой не включать класс tzinfo для UTC, потому что это достаточно непротиворечиво, чтобы иметь стандартную реализацию.

Изменить: Хотя в библиотеке нет реализации, в документе tzinfo приведена одна из приведенных ниже документации.

from datetime import timedelta, tzinfo

ZERO = timedelta(0)

# A UTC class.

class UTC(tzinfo):
    """UTC"""

    def utcoffset(self, dt):
        return ZERO

    def tzname(self, dt):
        return "UTC"

    def dst(self, dt):
        return ZERO

utc = UTC()

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

from datetime import datetime 

now = datetime.now(utc)

В Python 3.2 + есть datetime.timezone.utc:

from datetime import datetime, timezone 

now = datetime.now(timezone.utc)

Ответ 3

Обратите внимание, что для Python 3.2 и далее модуль datetime содержит datetime.timezone. В документации для datetime.utcnow() говорится:

Знающее текущее время и время UTC можно получить, вызвав datetime.now ( timezone.utc ).

Итак, вы можете сделать:

>>> import datetime
>>> datetime.datetime.now(datetime.timezone.utc)
datetime.datetime(2014, 7, 10, 2, 43, 55, 230107, tzinfo=datetime.timezone.utc)

Ответ 4

Модуль pytz является одним из параметров, и есть еще один python-dateutil, который, хотя он также является сторонним пакетом, уже доступен в зависимости от ваших других зависимостей и операционной системы.

Я просто хотел включить эту методологию для ссылки - если вы уже установили python-dateutil для других целей, вы можете использовать ее tzinfo вместо дублирования с помощью pytz

import datetime
import dateutil.tz

# Get the UTC time with datetime.now:
utcdt = datetime.datetime.now(dateutil.tz.tzutc())

# Get the UTC time with datetime.utcnow:
utcdt = datetime.datetime.utcnow()
utcdt = utcdt.replace(tzinfo=dateutil.tz.tzutc())

# For fun- get the local time
localdt = datetime.datetime.now(dateutil.tz.tzlocal())

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

Ответ 5

Жюльен Данджу написал хорошую статью, объясняющую почему вы никогда не должны иметь дело с часовыми поясами. Выдержка:

Действительно, API-интерфейс Datetime Python всегда возвращает недопустимые объекты datetime, что очень печально. Действительно, как только вы получите один из этих объекта, нет способа узнать, что такое часовой пояс, поэтому эти объекты довольно "бесполезны" сами по себе.

Увы, хотя вы можете использовать utcnow(), вы все равно не увидите информацию о часовом поясе, как вы обнаружили.

Рекомендации:

  • Всегда используйте известные объекты datetime, т.е. информацию о часовом поясе. Что убедитесь, что вы можете сравнивать их напрямую (осознавая и не осознавая datetimeобъекты не сопоставимы) и вернет их правильно пользователям. Используйте pytz, чтобы иметь объекты часового пояса.

  • Используйте ISO 8601 как входной и формат выходной строки. Используйте datetime.datetime.isoformat() для возврата timestamps как строка, форматированная с использованием этого формата, которая включает в себя информация о часовом поясе.

  • Если вам нужно проанализировать строки, содержащие временные метки формата ISO 8601, вы можете положиться на iso8601, который возвращает отметки времени с правильными информация о часовом поясе. Это делает отметки времени сопоставимыми.

Ответ 6

import datetime

>>> d = datetime.datetime.now(tz=datetime.timezone.utc)
>>> print(d.tzinfo)
'UTC+00:00'

Ответ 7

from datetime import datetime 
from dateutil.relativedelta import relativedelta
d = datetime.now()
date = datetime.isoformat(d).split('.')[0]
d_month = datetime.today() + relativedelta(months=1)
next_month = datetime.isoformat(d_month).split('.')[0]

Ответ 8

Даты UTC не нуждаются в информации о часовом поясе, так как это UTC, что по определению означает, что у них нет смещения.