Часовой пояс в ботах для Telegram

Часто при разработке ботов для Telegram требуется учитывать информацию о часовом поясе пользователя. К сожалению, получить её через Bot API невозможно, поэтому предусматривать в боте команду, с помощью которой пользователь сможет указать, какой часовой пояс он использует. И тут возникает вопрос, как лучше это сделать, чтобы пользователю было удобно. Если бот ориентирован только на российских пользователей, вопрос решается просто: выводим список всех часовых поясов России, пользователь выбирает нужный, и бот сохраняет выбор в базу данных.
Но как быть, если пользователи могут быть из других стран? Выводить огромный список из более чем сотни часовых поясов — крайне неудобно. Требовать от пользователя вручную написать название его часового пояса в формате Europe/Moscow или хотя бы MSK — тоже не самое лучшее решение. Можно предложить указать смещение в формате ±ЧЧ:ММ, но тогда нельзя будет учесть переход на летнее время.

В поисках более удобного решения я наткнулся на модули tzwhere и geopy. Первый позволяет определить часовой пояс для того или иного местоположения, заданного с помощью координат. Второй — получить эти самые координаты по названию города, причём позволяет это делать через Google Maps API, API Яндекс.Карт и ещё почти десяток сервисов. Я решил использовать Nominatim (это сервис Open Street Maps), так как он не требует получения tokenа, в отличие от Яндекс и Google, и при этом понимает названия городов и на английском языке, и на русском.
В итоге код определения часового пояса выглядит примерно так:
import geopy from tzwhere import tzwhere import datetime import pytz def get_timezone(bot,chat_id,city): geo = geopy.geocoders.Nominatim(user_agent="SuperMon_Bot") location = geo.geocode(city) # преобразуе if location is None: bot.send_message(chat_id,"Не удалось найти такой город. Попробуйте написать его название латиницей или указать более крупный город поблизости.") else: tzw = tzwhere.tzwhere() timezone_str = tzw.tzNameAt(location.latitude,location.longitude) # получаем название часового пояса tz = pytz.timezone(timezone_str) tz_info = datetime.datetime.now(tz=tz).strftime("%z") # получаем смещение часового пояса tz_info = tz_info[0:3]+":"+tz_info[3:] # приводим к формату ±ЧЧ:ММ bot.send_message(chat_id,"Часовой пояс установлен в %s (%s от GMT)." % (timezone_str,tz_info)) # здесь должно быть сохранение выбранной строки в БД return timezone_str
Приведение даты к нужному часовому поясу перед выводом пользователю делается либо с помощью метода tz.localize(dt) (для так называемых naive date, то есть не содержащих информацию о часовом поясе), либо с помощью метода dt.astimezone(tz), где dt — объект класса datetime, а tz — timezone.