Files
kandrusyak_bot/assistant_bot/reminders.py
kandrusyak 6667e0d253 init
2026-07-25 15:07:53 +03:00

65 lines
2.6 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import re
from datetime import datetime, timedelta, timezone
from zoneinfo import ZoneInfo
from .models import ReminderParseResult
from .time_utils import utc_now
def unit_to_timedelta(amount: int, unit: str) -> timedelta | None:
normalized = unit.lower().strip(".")
if normalized in {"s", "sec", "secs", "second", "seconds", "с", "сек", "секунд"}:
return timedelta(seconds=amount)
if normalized in {"m", "min", "mins", "minute", "minutes", "м"} or normalized.startswith("мин"):
return timedelta(minutes=amount)
if normalized in {"h", "hr", "hrs", "hour", "hours", "ч"} or normalized.startswith("час"):
return timedelta(hours=amount)
if normalized in {"d", "day", "days", "д"} or normalized.startswith(("дн", "ден")):
return timedelta(days=amount)
return None
def parse_reminder(raw_text: str, tz: ZoneInfo) -> ReminderParseResult | None:
text = raw_text.strip()
if not text:
return None
relative_match = re.match(r"^(?:через\s+)?(\d+)\s*([a-zа-я.]+)\s+(.+)$", text, re.IGNORECASE)
if relative_match:
amount = int(relative_match.group(1))
delta = unit_to_timedelta(amount, relative_match.group(2))
reminder_text = relative_match.group(3).strip()
if delta and reminder_text:
return ReminderParseResult(utc_now() + delta, reminder_text)
now_local = datetime.now(tz)
absolute_patterns = (
(r"^(\d{4}-\d{2}-\d{2})\s+(\d{1,2}:\d{2})\s+(.+)$", "%Y-%m-%d %H:%M"),
(r"^(\d{1,2}\.\d{1,2}\.\d{4})\s+(\d{1,2}:\d{2})\s+(.+)$", "%d.%m.%Y %H:%M"),
)
for pattern, date_format in absolute_patterns:
match = re.match(pattern, text)
if not match:
continue
naive = datetime.strptime(f"{match.group(1)} {match.group(2)}", date_format)
remind_at = naive.replace(tzinfo=tz)
reminder_text = match.group(3).strip()
if reminder_text:
return ReminderParseResult(remind_at.astimezone(timezone.utc), reminder_text)
time_match = re.match(r"^(\d{1,2}:\d{2})\s+(.+)$", text)
if time_match:
hour, minute = (int(part) for part in time_match.group(1).split(":", 1))
if 0 <= hour <= 23 and 0 <= minute <= 59:
remind_at = now_local.replace(hour=hour, minute=minute, second=0, microsecond=0)
if remind_at <= now_local:
remind_at += timedelta(days=1)
reminder_text = time_match.group(2).strip()
if reminder_text:
return ReminderParseResult(remind_at.astimezone(timezone.utc), reminder_text)
return None