Чому datetime.datetime.utcnow () не містить інформації про часовий пояс?


285
datetime.datetime.utcnow()

Чому для цього datetimeнемає жодної інформації про часовий пояс, враховуючи, що це явно UTC datetime?

Я би сподівався, що це буде містити tzinfo.


Як конвертувати звичайне поле дати формату iso, яке є рядковим типом, у формат utc?
Наві

Відповіді:


192

Це означає, що це наївний часовий пояс, тому з ним не можна користуватися 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), тобто працює для часових поясів, які можуть мати різний зміщення ультразвукового режиму в різний час (нефіксований зміщення потужності). Не використовуйте tz.localize(datetime.now())- це може вийти з ладу під час переходу на кінець DST, коли місцевий час неоднозначний.


216
Але немає вагомих причин, щоб це було наївним часовим поясом - воно вказано як UTC. Чому потрібно шукати сторонні бібліотеки, щоб вона працювала належним чином?
Марк Рансом

4
Я згоден; для мене "наївні" часи абсолютно марні. Наразі в списку python обговорюється питання про додавання pytz до stdlib; Проблема полягає не в ліцензуванні, а в тому, що дані часового поясу оновлюються так часто (чого сам Python не може бути). Також pytz не реалізує інтерфейс tzinfo очікуваним способом, тому ви можете помилитися, якщо спробувати використовувати деякі часові пояси міста astimezone. Таким чином, у datetime не тільки немає власних часових поясів, але єдина широкодоступна реалізація tzinfo не відповідає передбачуваному стандарту.
bobince

5
@bobince Чому pytz та стандартні бібліотеки дат не працюють для вас? Ядро Python та pytz, що розвиваються як незалежні проекти, зменшують логістичну складність основної команди. Так, зменшення складності для основної команди Python збільшує складність для всіх користувачів Python, яким потрібно мати справу з часовими поясами, але, я вірю, що вони прийняли це рішення з вагомих причин. Правило "У стандартній бібліотеці немає екземплярів tzinfo ..." чудово, тому що це просто, навіщо робити тут виняток?
Дерек Ліц

15
А як щодоu=datetime.now(pytz.utc)
Крейг МакКуїн

4
@bain: не використовувати tz.localize(datetime.now()); використовувати datetime.now(tz)замість цього.
jfs

142

Зауважте, що для 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)

2
Що переважніше? datetime.now(timezone.utc)або datetime.utcnow(timezone.utc)?
Джессі Вебб

8
datetime.utcnow()не бере аргументів. Так і мало бути datetime.now(timezone.utc).
Крейг МакКуїн

1
datetime.now()поверне машинний час, але datetime.utcnow()поверне фактичний час UTC.
Бабу

13
@Babu: datetime.utcnow()не встановлено, tzinfoщоб вказати, що це UTC. Але datetime.now(datetime.timezone.utc)повертає час UTC з tzinfo встановленим.
Крейг МакКуїн

@CraigMcQueen Отже, якщо ми передамо tzоб'єкт у теперішній конструктор, він поверне час цього часового поясу? Гаразд! Дякуємо, що вказали.
Бабу

71

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

Щоб використовувати його, щоб отримати поточний час як усвідомлений об'єкт дати:

from datetime import datetime 

now = datetime.now(utc)

Є datetime.timezone.utcв Python 3.2+:

from datetime import datetime, timezone 

now = datetime.now(timezone.utc)

8
Подумайте, чому цей клас не був наданий в першу чергу (і, що ще важливіше, використовується для datetimeстворених об'єктами utcnow()) ...
Андре Карон

17
Об'єкт часового поясу timezone.utcнарешті додано до Python 3.2. Для зворотної сумісності utcnow()все одно повертає часовий об'єкт без часового поясу, але ви можете отримати те, що хочете, зателефонувавши now(timezone.utc).
mhsmith

4
@rgove, це такий спосіб виправлення помилок, який повинен був бути справедливою грою для Python 3. Вони не повинні були турбуватися про відсталі сумісність. Ще один приклад, який я прочитав протягом останніх кількох днів - structмодуль здійснював би автоматичні перетворення з Unicode в bytestring, і остаточне рішення полягало в порушенні сумісності з більш ранніми версіями Python 3, щоб запобігти тому, щоб неправильне рішення не рухалося вперед.
Марк Викуп

2
Мене глузує, що tzinfoдокументація Python включає в себе приклади коду для його реалізації, але вони не включають цю функціональність у саму дату! docs.python.org/2/library/datetime.html#datetime.tzinfo.fromutc
LS

1
@LS так, pytzце чудовий ресурс. На той момент, коли я відредагував свою відповідь, щоб ввести приклад коду, хтось ще запропонував це, і я не хотів красти їхній грім.
Марк Рансом

20

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. Я підозрюю, що це не включено, оскільки в натільній бібліотеці дат за замовчуванням існують наївні дати для перехресної сумісності.


1
NameError: ім'я 'dt' не визначено
xApple

Я використовував виклик datetime.datetime.utcfromtimestamp (), і мені потрібно було додати tzinfo, друге рішення працювало на мене: utcdt = datetime.datetime.utcfromtimestamp(1234567890).replace(dateutil.tz.tzutc())
Ian Lee

1
зауважте: на відміну від datetime.now(pytz_tz)цього завжди працює; datetime.now(dateutil.tz.tzlocal())може вийти з ладу під час переходу DST . PEP 495 - Розбіжність у часі з місцевим часом може покращити dateutilситуацію в майбутньому.
jfs

@IanLee: ви можете використати utc_dt = datetime.fromtimestamp(1234567890, dateutil.tz.tzutc())(зауважте: dateutilз нефіксованим зміщенням utc (наприклад dateutil.tz.tzlocal()), можливо, тут не вдасться , замість цього використовуйте рішення на pytzоснові базування ).
jfs

Оскільки моя програма вже імпортування dateutilдля dateutil.parser, мені сподобалося це рішення краще. Це було так просто , як: utcCurrentTime = datetime.datetime.now(tz=dateutil.tz.tzutc()). Віола !!
LS

11

Жульєн Даньджу написав хорошу статтю, в якій пояснив, чому ніколи не слід мати справу з часовими поясами . Уривок:

Дійсно, API datetime Python завжди повертає невідомі об’єкти datetime, що дуже прикро. Дійсно, як тільки ви отримуєте один з цього об’єкта, немає ніякого способу дізнатися, що таке часовий пояс, тому ці об’єкти самі по собі є досить «марними».

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

Рекомендації:

  • Завжди використовуйте обізнані datetimeоб'єкти, тобто з інформацією про часовий пояс. Це гарантує можливість їх безпосереднього порівняння (свідомі та необізнані datetime об’єкти не порівнянні) та поверне їх правильно користувачам. Використовуйте пітс, щоб мати об'єкти часового поясу.

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

  • Якщо вам потрібно проаналізувати рядки, що містять часові позначки у форматі ISO 8601, ви можете розраховувати на те iso8601, що повертає часові позначки з правильною інформацією про часовий пояс. Це робить часові позначки безпосередньо порівнянними.


1
Це дещо оманлива рекомендація. Найголовніше правило - ніколи не торкайтеся часових поясів. Завжди зберігайте і передайте tz невідомі utc об’єкти (об'єкти епохи). Часовий пояс слід розраховувати лише під час представлення в інтерфейсі
нех

1
Це звучить так, що це вже досить добре відповідає думкам Жульєна. Які його конкретні рекомендації (як зазначено вище) вводять в оману?
Джо Д'Андреа

10

Щоб додати timezoneінформацію в Python 3.2+

import datetime

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

1
AttributeError: 'module' object has no attribute 'timezone' Python 2.7.13 (за замовчуванням, 19 січня 2017, 14:48:08)
Marcin Owsiany

-6
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]

-13

Дати UTC не потребують інформації про часовий пояс, оскільки вони є UTC, що за визначенням означає, що вони не мають зміщення.


10
Наскільки я можу сказати з docs.python.org/library/datetime.html , час дати без tzinfo - це той, де часовий пояс не визначено. Тут тимчасова зона була задана, тому логічно вона має бути присутня. Існує велика різниця між датою / часом без пов’язаного часового поясу і тим, що визначено в UTC. (В ідеалі вони повинні бути різними типами IMO, але це інша справа ...)
Джон Скіт,

@JonSkeet Я думаю, що ви пропускаєте думку Ігнасіо, що UTC не є часовим поясом. Дивно, що ця відповідь має -9 балів, коли я набираю це ...
CS

3
@CS: Ну Ігнасіо ніколи не заявляв, що ... і, строго кажучи, UTC не є часовим поясом, його зазвичай розглядають як життя, щоб зробити життя значно простішим (в тому числі в Python, наприклад, зpytz.utc ). Зауважте, що велика різниця між значенням, зсув якого від UTC невідомий, і значенням, де воно, як відомо, дорівнює 0. Останнє - те, що utcnow() має повернутись, IMO. Це вписується в "Усвідомлений об'єкт використовується для відображення конкретного моменту часу, який не піддається інтерпретації" відповідно до документації.
Джон Скіт
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.