[Перевод] Мега-Учебник Flask Глава 12: Дата и время (издание 2024)
Это двенадцатая часть серии мега-учебника Flask, в которой я собираюсь рассказать вам, как работать с датами и временем таким образом, чтобы это работало для всех ваших пользователей, независимо от того, где они проживают.
Оглавление
Один из аспектов моего приложения для ведения микроблогов, который я долгое время игнорировал, — это отображение дат и времени. До сих пор я просто позволял Python отображать объект datetime
в модели User
и даже не потрудился отобразить его в модели Post
. В этой главе вы узнаете, как работать с этими временными метками.
Ссылки на GitHub для этой главы: Browse, Zip, Diff.
Адский часовой пояс
Использование Python на сервере для отображения дат и времени, которые отображаются пользователям в их веб-браузерах, на самом деле не очень хорошая идея, потому что то, что сервер считает своим местным временем, не будет иметь смысла для пользователей, которые живут в другом часовом поясе.
Совершенно ясно, что сервер должен управлять временем, которое является согласованным и независимым от его собственного местоположения и местоположения пользователей. Если это приложение разрастется до такой степени, что потребуется несколько производственных серверов в разных регионах мира, я бы не хотел, чтобы каждый сервер записывал временные метки в базу данных в разных часовых поясах, потому что это сделало бы невозможной работу с этими временами. Поскольку UTC является наиболее используемым единым часовым поясом и поддерживается в классе datetime
, именно его я и собираюсь использовать.
В главе 4 вы видели, как создавать временные метки UTC для записей в блоге. В качестве напоминания, вот краткий пример, показывающий, как это было сделано.:
>>> from datetime import datetime, timezone
>>> str(datetime.now(timezone.utc))
'2023-11-19 19:05:51.288261+00:00'
Но с этим подходом связана важная проблема. Пользователям из разных мест будет ужасно сложно определить, когда была сделана публикация, если они будут видеть время в часовом поясе UTC. Им нужно было бы заранее знать, что время указано в UTC, чтобы они могли мысленно подогнать его к своему собственному часовому поясу. Представьте пользователя, скажем, в часовом поясе PDT на Западном побережье США, который публикует что-то в 15: 00 и сразу видит, что сообщение появляется в 10: 00 по времени UTC, или, если быть более точным, в 22: 00. Это будет очень запутанно.
Хотя стандартизация временных меток в соответствии с UTC имеет большой смысл с точки зрения сервера, это создает проблему удобства использования для пользователей. Цель этой главы — представить решение, которое сохраняет все временные метки, управляемые сервером, в часовом поясе UTC, не отталкивая пользователей.
Преобразование часовых поясов
Очевидным решением проблемы является преобразование всех временных меток из сохраненных единиц UTC в местное время каждого пользователя при их отображении. Это позволяет серверу продолжать использовать UTC для обеспечения согласованности, в то время как преобразование «на лету», адаптированное к каждому пользователю, решает проблему удобства использования. Сложная часть этого решения — знать местоположение каждого пользователя.
На многих веб-сайтах есть страница конфигурации, где пользователи могут указывать свой часовой пояс. Для этого мне потребуется добавить новую страницу с формой, в которой я представляю пользователям раскрывающийся список часовых поясов. При первом входе на сайт пользователей могут попросить ввести их часовой пояс в рамках регистрации.
Хотя это достойное решение, решающее проблему, немного странно просить пользователей вводить часть информации, которую они уже настроили в своей операционной системе. Кажется, было бы эффективнее, если бы я мог просто получить настройки часового пояса с их компьютеров.
Как выясняется, веб-браузер знает часовой пояс пользователя и предоставляет его через стандартные API JavaScript даты и времени. На самом деле есть два способа воспользоваться информацией о часовом поясе, доступной через JavaScript:
Подход «старой школы» заключался бы в том, чтобы веб-браузер каким-то образом отправлял информацию о часовом поясе на сервер, когда пользователь впервые входит в приложение. Это можно было бы сделать с помощью вызова Ajax или гораздо проще с помощью мета-тега обновления. Как только сервер узнает часовой пояс, он может сохранить его в сеансе пользователя или записать в таблицу users в базе данных, и с этого момента корректировать с его помощью все временные метки во время отображения шаблонов.
Подход «новой школы» заключается в том, чтобы ничего не менять на сервере и позволить преобразованию UTC в местный часовой пояс происходить в браузере с использованием JavaScript.
Оба варианта допустимы, но второй имеет большое преимущество. Знания часового пояса пользователя не всегда достаточно для представления дат и времени в формате, ожидаемом пользователем. Браузер также имеет доступ к конфигурации языкового стандарта системы, которая определяет такие параметры, как время утра / вечера в сравнении с 24-часовыми часами, формат отображения даты DD / MM / ГГГГ в сравнении с MM / DD / ГГГГ и многие другие культурные или региональные стили.
И если этого недостаточно, у подхода новой школы есть еще одно преимущество. Есть библиотека с открытым исходным кодом, которая выполняет всю эту работу!
Знакомство Moment.js и Flask-Moment
Moment.js это небольшая библиотека JavaScript с открытым исходным кодом, которая выводит отображение даты и времени на новый уровень, поскольку предоставляет все мыслимые варианты форматирования, а затем и некоторые другие. Некоторое время назад я создал Flask-Moment, небольшое расширение Flask, которое позволяет очень легко интегрировать moment.js в ваше приложение.
Итак, давайте начнем с установки Flask-Moment:
(venv) $ pip install flask-moment
Это расширение добавляется в приложение Flask обычным способом:
app/__init__.py: Пример Flask-Moment.
# ...
from flask_moment import Moment
app = Flask(__name__)
# ...
moment = Moment(app)
# ...
В отличие от других расширений, Flask-Moment работает вместе с moment.js, поэтому все шаблоны приложения должны включать эту библиотеку. Чтобы гарантировать, что эта библиотека всегда доступна, я собираюсь добавить ее в базовый шаблон. Это можно сделать двумя способами. Самый прямой способ — явно добавить тег , который импортирует библиотеку, но Flask-Moment упрощает задачу, предоставляя функцию
moment.include_moment()
, которая генерирует тег :
app/templates/base.html: Включить moment.js в базовый шаблон.
...
{{ moment.include_moment() }}