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

datetime.datetime.utcnow()

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

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

10 ответов

Решение

Это означает, что это часовой пояс наивный, поэтому вы не можете использовать его с 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()) - может произойти сбой во время перехода в конце летнего времени, когда местное время неоднозначно.

Обратите внимание, что для 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)

Стандартные библиотеки 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)

Есть datetime.timezone.utc в Python 3.2+:

from datetime import datetime, timezone 

now = datetime.now(timezone.utc)

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. Я подозреваю, что это не включено, потому что собственная библиотека datetime по умолчанию имеет наивные datetime для перекрестной совместимости.

Добавить timezone информация в Python 3.2+

import datetime

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

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

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

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

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

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

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

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

Поведение datetime.datetime.utcnow()возвращение времени UTC как наивного объекта datetime, очевидно, проблематично и должно быть исправлено. Это может привести к неожиданному результату, если локальный часовой пояс вашей системы не является UTC, поскольку библиотека datetime предполагает наивный объект datetime для представления местного времени системы. Например, datetime.datetime.utcnow().timestaamp()дает метку времени на 4 часа вперед от правильного значения на моем компьютере. Кроме того, начиная с python 3.6, datetime.astimezone() можно вызывать на наивных экземплярах datetime, но datetime.datetime.utcnow().astimezone(any_timezone) дает неверный результат, если только местный часовой пояс вашей системы не является UTC.

Он должен включать и также. Связанная проблема.

Так до того, now()предпочтительнее today()а также utcnow().

      from datetime import datetime, timezone
utc = timezone.utc
date = datetime.now(utc)
print(date) # 2022-04-06 05:40:13.025347+00:00
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]

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

Другие вопросы по тегам