RU /EN
Start a project
← Selected projects
Case study

timesense

A deterministic natural-language parser for dates, events and recurrence — no LLM, no ML. “every second Friday of the month at 6:30pm retro” → a structured event, an RFC 5545 rrule or a ready .ics file. Russian and English, zero dependencies, under 1 ms per phrase.

What it is

A library that turns a natural-language phrase into a structured event. Not just a date and time: the event type, title, location, duration, recurrence rule and deadline.

"every second Friday of the month at 6:30pm retro in the meeting room"
  → event · title "retro" · location "in the meeting room"
  → 18:30 · FREQ=MONTHLY;BYDAY=2FR

The result exports to JSON, to an RFC 5545 rrule, or to a ready .ics file that opens in Google Calendar, Apple Calendar and Outlook.

Russian and English, with automatic language detection. Pure Python 3.9–3.13, zero required dependencies.

Why it exists

The problem shows up whenever there is voice input or a bot: a person says “move it to next Tuesday around six”, and the system needs a date, a time and a recurrence rule.

Existing date parsers — dateparser, parsedatetime — extract a datetime and stop there. They will not tell you the event repeats, will not hand you an rrule, and will not assemble an .ics. Everything past the timestamp is yours to write.

The other route is to send the phrase to an LLM. And that is where the real problem starts.

Why not an LLM

Calendar automation needs determinism: the same phrase must produce the same event every time. Not “almost always” — always.

A model does not guarantee that. On the same phrase it can return a different date after a version bump, at a different temperature, or simply on a different run. You cannot debug that behaviour: there is no place to look and see why this particular answer came out.

There is no machine learning inside timesense — only dictionaries and regular expressions. Everything else follows from that:

Metrictimesense
Required dependencies0 — standard library only
Models and GPUnot needed
Cold start~0.2 s
Memorya few MB
Latencyunder 1 ms per phrase, 1,000+ phrases/sec on a single modest core
Same input → same outputyes, always

The practical consequence: the parser can be called on every utterance of a live transcription, inline in the pipeline, and it runs on the cheapest VPS, on a Raspberry-Pi-class board, or inside a serverless function.

What’s inside

Three result types, selected automatically:

  • a point in time → ReminderResult
  • an interval with a start and an end → CalendarResult
  • a period, deadline, open start or fuzzy span → TaskResult

What it parses. Times (at 17:00, half past ten, quarter to eight), relative spans (in an hour and a half, in forty five minutes), dates (March 3rd, 3/17, ISO), ranges (from nine to five, including across midnight), recurrence (every weekday, every 2 weeks on Monday, every month on the 15th), deadlines (by end of March, by 5pm), duration and location.

Working calendar. Load public holidays and transferred working weekends, and “the last business day of the month” is computed correctly instead of meaning “the last Mon–Fri”.

Business-day arithmetic. two business days before end of month resolves to a concrete date against the loaded calendar.

Deliberate limitations

Time zones are not supported: every datetime is naive, with no tzinfo. A phrase carrying a zone (GMT+3, в 10 мск) deliberately returns None rather than a guess.

That is a choice, not an omission. Silently returning a zoneless time when the text had a zone is the worst available option: the error surfaces in the user’s calendar rather than in the code.

What came out of it

A stable 1.0.0 with a frozen public API, MIT licensed, published on PyPI, with tests in the repository and separate suites for the Russian and English grammars.