Как мне получить значение datetime.today() в Python, которое "учитывает часовой пояс"?

Я пытаюсь вычесть одно значение даты из значения datetime.today(), чтобы вычислить, как давно что-то было. Но это жалуется:

TypeError: can't subtract offset-naive and offset-aware datetimes

Значение datetime.today(), похоже, не "учитывает часовой пояс", в то время как мое другое значение даты -. Как получить значение datetime.today() с учетом часового пояса?

Прямо сейчас, это дает мне время по местному времени, которое является PST, то есть UTC - 8 часов. В худшем случае, есть ли способ, которым я могу вручную ввести значение часового пояса в объект datetime, возвращаемый datetime.today(), и установить его в UTC-8?

Конечно, идеальным решением было бы автоматическое определение часового пояса.

Ответ 1

В стандартной библиотеке нет кроссплатформенного способа создания осведомленных часовых поясов без создания собственного класса часовых поясов.

На Windows есть win32timezone.utcnow(), но это часть pywin32. Я бы предпочел использовать библиотеку pytz, в которой постоянно обновляется база данных большинства часовых поясов.

Работа с местными часовыми поясами может быть очень сложной (см. ссылки "Дальнейшее чтение" ниже), поэтому вы, скорее всего, захотите использовать UTC во всем приложении, особенно для арифметических операций, таких как вычисление разницы между двумя временными точками.

Вы можете получить текущую дату/время следующим образом:

import pytz
from datetime import datetime
datetime.utcnow().replace(tzinfo=pytz.utc)

Помните, что datetime.today() и datetime.now() возвращают местное время, а не время UTC, поэтому применение .replace(tzinfo=pytz.utc) к ним будет неправильным.

Еще один хороший способ сделать это:

datetime.now(pytz.utc)

который немного короче и делает то же самое.


Дальнейшее чтение/просмотр, почему во многих случаях предпочитаете UTC:

Ответ 2

Получить текущее время в определенном часовом поясе:

import datetime
import pytz
my_date = datetime.datetime.now(pytz.timezone('US/Pacific'))

Ответ 3

В Python 3 стандартная библиотека значительно упрощает указание UTC в качестве часового пояса:

>>> import datetime
>>> datetime.datetime.now(datetime.timezone.utc)
datetime.datetime(2016, 8, 26, 14, 34, 34, 74823, tzinfo=datetime.timezone.utc)

Если вам нужно решение, которое использует только стандартную библиотеку и работает как в Python 2, так и в Python 3, см. J. Ф. Себастьян, ответ.

Ответ 4

Вот решение stdlib, которое работает как на Python 2, так и на 3:

from datetime import datetime

now = datetime.now(utc) # Timezone-aware datetime.utcnow()
today = datetime(now.year, now.month, now.day, tzinfo=utc) # Midnight

где today - это осведомленный экземпляр datetime, представляющий начало дня (полночь) в UTC, а utc - объект tzinfo (пример из документации):

from datetime import tzinfo, timedelta

ZERO = timedelta(0)

class UTC(tzinfo):
    def utcoffset(self, dt):
        return ZERO

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

    def dst(self, dt):
        return ZERO

utc = UTC()

Связано: сравнение производительности нескольких способов получить полночь (начало дня) для указанного времени UTC. Примечание. Более сложно получить полночь для часового пояса с нефиксированным смещением UTC.

Ответ 5

Другой метод для создания объекта datetime, поддерживающего зону времени, представляющий текущее время:

import datetime
import pytz

pytz.utc.localize( datetime.datetime.utcnow() )  

Ответ 6

Если вы используете Django, вы можете установить даты, не поддерживающие tz (только UTC).

Прокомментируйте следующую строку в settings.py:

USE_TZ = True

Ответ 7

pytz - это библиотека Python, которая позволяет выполнять точные и кросс-платформенные вычисления часового пояса с использованием Python 2.3 или выше.

С помощью stdlib это невозможно.

См. аналогичный вопрос fooobar.com/questions/15453/....

Ответ 8

Вот один из способов сгенерировать его с помощью stdlib:

import time
from datetime import datetime

FORMAT='%Y-%m-%dT%H:%M:%S%z'
date=datetime.strptime(time.strftime(FORMAT, time.localtime()),FORMAT)

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

date
datetime.datetime(2017, 8, 1, 12, 15, 44, tzinfo=datetime.timezone(datetime.timedelta(0, 7200)))

date.tzname()
'UTC+02:00'

Ключ добавляет директиву %z к представлению FORMAT, чтобы указать смещение UTC сгенерированной структуры времени. Другие форматы представлений можно проконсультироваться в модуле datetime docs

Если вам нужна дата в часовой пояс UTC, вы можете заменить time.localtime() на time.gmtime()

date=datetime.strptime(time.strftime(FORMAT, time.gmtime()),FORMAT)

date    
datetime.datetime(2017, 8, 1, 10, 23, 51, tzinfo=datetime.timezone.utc)

date.tzname()
'UTC'

Edit

Это работает только на python3. Директива z недоступна на python 2 _ strptime.py code

Ответ 10

Однострочник, использующий только стандартную библиотеку, работает, начиная с Python 3.3. Вы можете получить объект datetime, осведомленный о местном часовом поясе, используя astimezone (как предложено johnchen902):

from datetime import datetime, timezone

aware_local_now = datetime.now(timezone.utc).astimezone()

print(aware_local_now)
2019-08-02 11:26:32.341817-07:00

Ответ 11

Получение даты, относящейся к часовому поясу, в часовом поясе utc достаточно для работы с вычитанием даты.

Но если вы хотите получить информацию о часовом поясе в вашем текущем часовом поясе, tzlocal - это способ:

from tzlocal import get_localzone  # pip install tzlocal
from datetime import datetime
datetime.now(get_localzone())

PS dateutil имеет аналогичную функцию (dateutil.tz.tzlocal). Но, несмотря на то, что он разделяет имя, он имеет совершенно другую базу кода, которая, как отмечает Дж. Ф. Себастьяна, может дать неправильные результаты.

Ответ 12

Если вы получаете текущее время и дату в python, тогда импортируйте дату и время, пакет pytz в python после того, как вы получите текущую дату и время, например..

from datetime import datetime
import pytz
import time
str(datetime.strftime(datetime.now(pytz.utc),"%Y-%m-%d %H:%M:%S%t"))

Ответ 13

Используйте часовой пояс, как показано ниже, для времени с учетом часового пояса. По умолчанию установлено UTC:

from django.utils import timezone
today = timezone.now()

Ответ 14

Специально для часовых поясов без UTC:

Единственный часовой пояс, который имеет собственный метод, - это timezone.utc, но вы можете пометить часовой пояс с любым смещением UTC, если вам нужно, используя timedelta & timezone и принудительное его использование .replace.

In [1]: from datetime import datetime, timezone, timedelta

In [2]: def force_timezone(dt, utc_offset=0):
   ...:     return dt.replace(tzinfo=timezone(timedelta(hours=utc_offset)))
   ...:

In [3]: dt = datetime(2011,8,15,8,15,12,0)

In [4]: str(dt)
Out[4]: '2011-08-15 08:15:12'

In [5]: str(force_timezone(dt, -8))
Out[5]: '2011-08-15 08:15:12-08:00'

Использование timezone(timedelta(hours=n)) в качестве часового пояса - это настоящая серебряная пуля, и у него много других полезных приложений.

Ответ 15

Другая альтернатива, на мой взгляд, лучше, использует Pendulum вместо pytz. Рассмотрим следующий простой код:

>>> import pendulum

>>> dt = pendulum.now().to_iso8601_string()
>>> print (dt)
2018-03-27T13:59:49+03:00
>>>

Чтобы установить Pendulum и просмотреть их документацию, перейдите сюда. У него множество опций (например, простая поддержка ISO8601, RFC3339 и многих других форматов), лучшая производительность и, как правило, более простой код.