#!/usr/bin/env python3 # utils.py from datetime import datetime, date from typing import List, Optional from zoneinfo import ZoneInfo from telegram import ReplyKeyboardMarkup, InlineKeyboardMarkup, InlineKeyboardButton from config import BTN_ADD, BTN_LIST, BTN_EDIT, BTN_DELETE, BTN_HISTORY, BTN_TZ, BTN_CANCEL, TZ_SUGGESTIONS # ----------------- UI HELPERS ----------------- def main_menu_kb(): kb = [ [BTN_ADD, BTN_LIST], [BTN_EDIT, BTN_DELETE], [BTN_HISTORY, BTN_TZ] ] return ReplyKeyboardMarkup(kb, resize_keyboard=True, one_time_keyboard=False) def tz_keyboard(): kb = [[tz] for tz in TZ_SUGGESTIONS] kb.append(["Ввести вручную"]) kb.append([BTN_CANCEL]) return ReplyKeyboardMarkup(kb, one_time_keyboard=True, resize_keyboard=True) def build_wd_keyboard(wd_sel: set): labels = ["Пн", "Вт", "Ср", "Чт", "Пт", "Сб", "Вс"] kb = [] row = [] for i, lab in enumerate(labels): prefix = "✅" if i in wd_sel else "◻️" row.append(InlineKeyboardButton(f"{prefix} {lab}", callback_data=f"wd_toggle:{i}")) if (i + 1) % 3 == 0: kb.append(row) row = [] if row: kb.append(row) kb.append([ InlineKeyboardButton("Готово", callback_data="wd_done"), InlineKeyboardButton("Отмена", callback_data="wd_cancel") ]) return InlineKeyboardMarkup(kb) # ----------------- DATA HELPERS ----------------- def parse_hhmm(s: str) -> Optional[str]: s = s.strip() try: dt = datetime.strptime(s, "%H:%M") return dt.strftime("%H:%M") except ValueError: return None def weekdays_list_to_csv(lst: List[int]) -> str: return ",".join(str(i) for i in sorted(set(lst))) if lst else "" def weekdays_csv_to_list(csv: Optional[str]) -> List[int]: if not csv: return [] return [int(x) for x in csv.split(",") if x.isdigit()] def now_utc() -> datetime: return datetime.utcnow() def utc_str_min(dt: datetime) -> str: return dt.strftime("%Y-%m-%d %H:%M") def utc_str_full(dt: datetime) -> str: return dt.strftime("%Y-%m-%d %H:%M:%S") def localized_now_for_tz(tzname: str) -> datetime: try: tz = ZoneInfo(tzname) except Exception: tz = ZoneInfo("UTC") return datetime.now(tz) def local_time_hhmm_for_user(tzname: str, when_utc: datetime) -> str: try: tz = ZoneInfo(tzname) except Exception: tz = ZoneInfo("UTC") local = when_utc.astimezone(tz) return local.strftime("%H:%M") def user_local_hhmm_to_utc_dt(tzname: str, local_date: date, hhmm: str) -> datetime: hour, minute = map(int, hhmm.split(":")) local_dt = datetime(local_date.year, local_date.month, local_date.day, hour, minute) try: tz = ZoneInfo(tzname) local_dt = local_dt.replace(tzinfo=tz) except Exception: tz = ZoneInfo("UTC") local_dt = local_dt.replace(tzinfo=tz) return local_dt.astimezone(ZoneInfo("UTC")).replace(tzinfo=None)