Посты с тэгом datetime


[Перевод] «Eppur si muove!»* или Работаем с таймзонами в Python


На нашей планете Земля, в одно и то же время, в разных географических точках планеты может быть разное время суток. Это следствие того, что наш мир — вращающийся геоид, а не плоский диск, а что наша Солнечная система имеет только одну звезду — Солнце. Ещё со школы всем известно о часовых поясах, и все мы встречались с их проявлениями в реальной жизни («Московское время – 15 часов, в Петропавловске-Камчатском – полночь», джетлаг при дальних перелётах, и т.д.). К несчастью, часовые пояса всего лишь частично основаны на физических особенностях нашего мира, и при компьютерных вычислениях приходится учитывать другие, порой неожиданные, нюансы.

* «И всё-таки она вертится!» — крылатая фраза, которую якобы произнёс Галилео Галилей, покидая процесс инквизиции после отречения от своего убеждения в том, что Земля вращается вокруг Солнца. В нашем случае, увы, это вращение приводит ко всем этим «замечательным» проблемам с часовыми поясами.

Что общего у этой статьи и Галиле


Питон: еще раз форматирование

Хочу напомнить об одной занятной штуке, которую сам периодически забываю.

Как переводят дату-время в строку? Обычно так:

>>> from datetime import datetime
>>> d = datetime.now()
>>> d.strftime("%d.%m.%Y")
'25.10.2012'

А на самом деле можно и так:

>>> "{:%d.%m.%Y}".format(d)
'25.10.2012'

Как это работает?

.format разбирает строку формата и определяет параметры форматирования для аргументов. Для первого аргумента, очевидно, это %d.%m.%Y.

Это значение попадает в метод .__format__ в качестве аргумента, а результат вызова подставляется в шаблон:

>>> d.__format__("%d.%m.%Y")
'25.10.2012'

Что это дает? Можно коротко и элегантно записывать сложные шаблоны:

>>> "{} — {:%d.%m.%Y}".format("Today", d)
'Today — 25.10.2012'

То же самое работает и для других класс



Питон: еще раз форматирование

Хочу напомнить об одной занятной штуке, которую сам периодически забываю.

Как переводят дату-время в строку? Обычно так:

>>> from datetime import datetime
>>> d = datetime.now()
>>> d.strftime("%d.%m.%Y")
'25.10.2012'

А на самом деле можно и так:

>>> "{:%d.%m.%Y}".format(d)
'25.10.2012'

Как это работает?

.format разбирает строку формата и определяет параметры форматирования для аргументов. Для первого аргумента, очевидно, это %d.%m.%Y.

Это значение попадает в метод .__format__ в качестве аргумента, а результат вызова подставляется в шаблон:

>>> d.__format__("%d.%m.%Y")
'25.10.2012'

Что это дает? Можно коротко и элегантно записывать сложные шаблоны:

>>> "{} — {:%d.%m.%Y}".format("Today", d)
'Today — 25.10.2012'

То же самое работает и для других



Питон: времена, даты и временные зоны

В статье Питон: времена, даты и временные зоны я рассказывал, что такое абсолютное и относительное время в терминах Питона.

И упоминал, что сравнение относительного и абсолютного времени выбросит исключение TypeError. В Python 3.3 ситуация изменилась.

Относительное и абсолютное времена всё ещё нельзя сравнивать на упорядоченность (больше или меньше). Сравнение на эквивалентность никогда не срабатывает, при этом ошибки нет.

Пример:

>>> from datetime import datetime, timezone
>>> naive = datetime.now()
>>> aware = datetime.now(timezone.utc)
>>> naive < aware
Traceback (most recent call last):
  ...
TypeError: can't compare offset-naive and offset-aware datetimes
>>> naive == aware
False

Ещё раз подчеркиваю: относ



Питон: времена, даты и временные зоны

Сегодня поговорим о дате-времени.

При этом я не хочу отдельно останавливаться на модуле time - слишком он низкоуровневый.

Эта статья будет почти исключительно посвящена модулю datetime, предоставляющему довольно красивый и понятный интерфейс.

Давайте посмотрим на элементарный пример:

>>> from datetime import *
>>> dt = datetime.now()

Что может быть проще?

Правильно ли так писать? Ответ будет довольно неожиданным: когда как...

Дело в том, что в программах, как бы это парадоксально не звучало, одновременно существуют два типа времени, которые логически не перекрываются.

Назовем их относительным и абсолютным временем.

Относительное время

Этот тип времени никогда не пересекает границ программы, не сохраняется в базе данных и не передается по сети.

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



Сохранение времени в базе данных

Очень часто бывает, что практически все знают, как надо делать правильно, но при этом всё равно постоянно делают неправильно. Один из таких случаев — сохрание времени в базе данных. Понятно, что на персональном блоге вполне можно обойтись наивных подходом, не учитывающим перевод времени. Но для круглосуточно работающих приложений строгой системы отчётности вроде биллинга это неприемлемо.
Я не буду здесь рассматривать все возможные варианты корректной работы со временем. Покажу лишь насколько просто можно реализовать самый распространённый вариант — хранение в базе в UTC — на примере SQLAlchemy. Для этого достаточно определить новый тип колонки:
from sqlalchemy import types
from dateutil.tz import tzutc
from datetime import datetime

class UTCDateTime(types.TypeDecorator):

    impl = types.DateTime

    def process_bind_param(self, value, engine):
        if value is not None:
            return value.astimezone(tzutc())

    def process_res