Parse natural-language AFK (away-from-keyboard) phrases into concrete, timezone-aware start and end datetimes.
The core AFKParser uses parsedatetime under the hood and adds opinionated logic to infer sensible start/end windows for common AFK phrases used in everyday status updates, such as:
- "afk for 30 min"
- "afk till 8am"
- "afk today"
- "afk from 5pm"
- "will start late at 11am"
- "afk on monday"
- Features
- Installation
- Quick start
- Supported phrase patterns
- Development
- Testing
- Project structure
- API reference
- Requirements
- Limitations and notes
- Contributing
- License
- Natural language parsing powered by parsedatetime
- Timezone-aware results; you pass seconds offset from UTC
- Sensible defaults for day/week/month/year phrases (e.g., end-of-day windows)
- Thorough tests covering many common phrasings
git clone https://github.com/astr0n0mer/afk_parser.git
cd afk_parser
uv sync --lockedThis creates a local .venv and installs the package with its locked dependencies.
For runtime dependencies only:
uv sync --locked --no-devuv add afk-parserfrom datetime import datetime
from afk_parser.afk_parser import AFKParser
# Compute your local UTC offset in seconds (example)
utc_offset_seconds = datetime.now().astimezone().utcoffset().total_seconds()
parser = AFKParser()
result = parser.parse_dates("afk for 30 min", tz_offset=utc_offset_seconds)
if result is not None:
start_dt, end_dt = result
print(start_dt, end_dt)parse_dates returns a tuple (start_datetime, end_datetime) as timezone-aware datetime objects, or None if the phrase cannot be parsed.
Notes:
tz_offsetis a float representing seconds offset from UTC (e.g.,-18000for UTC-5).- The parser differentiates between single time points vs. ranges and applies rules like end-of-day for day-level accuracy.
Run the helper script with your phrase. It automatically infers your local UTC offset.
uv run --locked python main.py "afk from 5pm"Example output (two lines; ISO-8601 repr may vary):
2024-06-20 17:00:00-04:00
2024-06-20 23:59:59.999999-04:00
These examples are covered by tests and illustrate the behavior. Actual values depend on current date/time and timezone.
- Durations starting now: "afk for 30 min", "afk for 3 hours", "afk for 1 week"
- Until a specific time: "afk till 8am", "afk till 12pm"
- Whole-day windows: "afk today", "afk tomorrow"
- Start at time, end end-of-day: "afk from 5pm", "afk after 5:30pm", "afk post 5pm"
- Specific future times: "will start late at 11am", "will start late at 11am tomorrow"
- Specific days: "afk on monday"
- Month/year ranges: "afk for 1 month", "afk for 2 years" (interpreted as end-of-day windows on the target date)
Use uv to scaffold the environment and install dependencies from pyproject.toml and uv.lock.
# Install runtime + dev dependencies
uv sync --locked
# Install runtime dependencies only
uv sync --locked --no-devUseful commands:
uv sync --locked— create/update.venvwith locked runtime and dev dependenciesuv sync --locked --no-dev— install locked runtime dependencies onlyuv run --locked python main.py "afk from 5pm"— run the source CLIuv run --locked pytest ./afk_parser/tests -vv— run the test suiteuv run --locked pyright .— run type checksuv run --locked ruff format .— format the codebase
The Makefile wraps the same common tasks if you prefer make:
make install— runuv sync --locked --no-devmake install_dev— runuv sync --lockedmake upgrade_dependencies— upgrade locked dependenciesmake test— run the test suitemake lint— run type checks with Pyrightmake format— format with Ruff
Run the full test suite:
uv run --locked pytest ./afk_parser/tests -vvOr via the Makefile:
make testafk_parser/
afk_parser/
__init__.py
afk_parser.py # AFKParser implementation
tests/
test_afk_parser.py
main.py # Simple CLI wrapper (from source)
Makefile # Dev tasks (install, test, lint, format)
pyproject.toml # Project metadata and dependencies
uv.lock # Locked dependency versions
setup.py
class AFKParser:
def parse_dates(self, phrase: str, tz_offset: float = 0) -> tuple[datetime, datetime] | None- phrase: Natural-language AFK phrase
- tz_offset: Seconds offset from UTC (float). Use your local offset for local time results.
- Returns a
(start_datetime, end_datetime)pair as timezone-awaredatetimeobjects, orNoneif the phrase could not be parsed.
- Python 3.14+
uvparsedatetime(installed byuv sync --locked)
- Natural language can be ambiguous; not every phrasing is supported. See tests for covered cases.
- Day/month/year phrases are interpreted with end-of-day semantics for the target date.
- For two-part phrases like "from 4pm for 1 hr", the parser computes both start and end precisely to the second.
Issues and PRs are welcome. Before opening a PR, please:
uv run --locked ruff format .
uv run --locked pyright .
uv run --locked pytest ./afk_parser/tests -vvMIT © Imran Khan. See LICENSE for details.