Quando
A Taskwarrior-style date expression parser for Elixir. Parse expressions like +7d, eom, monday, or P1Y2M3D into DateTime structs using NimbleParsec.
Installation
Add quando to your list of dependencies in mix.exs:
def deps do
[
{:quando, "~> 0.1.0"}
]
endUsage
# Parse relative durations
{:ok, dt} = Quando.parse("+7d") # 7 days from now
{:ok, dt} = Quando.parse("-2w") # 2 weeks ago
{:ok, dt} = Quando.parse("+3m") # 3 months from now (m = months)
{:ok, dt} = Quando.parse("30min") # 30 minutes from now
# Parse chained durations
{:ok, dt} = Quando.parse("+1d+9h") # Tomorrow at this time + 9 hours
# Parse date synonyms
{:ok, dt} = Quando.parse("today") # Start of today
{:ok, dt} = Quando.parse("tomorrow") # Start of tomorrow
# Parse period boundaries
{:ok, dt} = Quando.parse("eom") # End of month
{:ok, dt} = Quando.parse("sow") # Start of week
# Parse day/month names
{:ok, dt} = Quando.parse("monday") # Next Monday
{:ok, dt} = Quando.parse("fri") # Next Friday
{:ok, dt} = Quando.parse("december") # December 1st
# Parse ordinals
{:ok, dt} = Quando.parse("15th") # 15th of current/next month
# Parse ISO-8601 durations
{:ok, dt} = Quando.parse("P3D") # 3 days from now
{:ok, dt} = Quando.parse("PT1H30M") # 1 hour 30 minutes from now
# Bang version raises on error
dt = Quando.parse!("+7d")
# Get the parsed AST without calculation
{:ok, ast} = Quando.parse_ast("+7d")
# => {:ok, {:chained_duration, [{:duration, %{sign: :+, amount: 7, unit: :days}}]}}Supported Syntax
Duration Offsets
| Expression | Description |
|---|---|
+7d, -3d, 5d | Days |
+2w, -1w | Weeks |
+3m, -2m |
Months (note: m = months) |
+1y, -2y | Years |
+5h, -2h | Hours |
30min, 45mins |
Minutes (use min/mins for minutes) |
+30s, -15sec | Seconds |
Chained Durations
Chain multiple durations together:
| Expression | Description |
|---|---|
+1d+9h | Tomorrow plus 9 hours |
-2w+3d | Two weeks ago plus 3 days |
+1y+2m+3d | 1 year, 2 months, 3 days from now |
Date Synonyms
| Expression | Description |
|---|---|
now | Current time |
today | Start of today (00:00:00) |
yesterday | Start of yesterday |
tomorrow | Start of tomorrow |
Day Names
Full names and abbreviations are supported:
monday, mon, tuesday, tue, wednesday, wed, thursday, thu, friday, fri, saturday, sat, sunday, sun
Returns the next occurrence of the specified day.
Month Names
Full names and abbreviations are supported:
january, jan, february, feb, march, mar, april, apr, may, june, jun, july, jul, august, aug, september, sep, october, oct, november, nov, december, dec
Returns the 1st of the next occurrence of the specified month.
Period Boundaries
| Expression | Description |
|---|---|
sow, socw | Start of week |
eow, eocw | End of week |
som, socm | Start of month |
eom, eocm | End of month |
soy, socy | Start of year |
eoy, eocy | End of year |
soq | Start of quarter |
eoq | End of quarter |
eod | End of day |
Ordinals
| Expression | Description |
|---|---|
1st, 2nd, 3rd | Day of month |
15th, 31st | Day of month |
Returns the specified day of the current month if not yet passed, otherwise the next month.
ISO-8601 Durations
| Expression | Description |
|---|---|
P3D | 3 days |
P2W | 2 weeks |
P1Y | 1 year |
P1Y2M3D | 1 year, 2 months, 3 days |
PT1H | 1 hour |
PT30M | 30 minutes |
PT45S | 45 seconds |
P1Y2M3DT12H40M50S | Complex duration |
Options
Reference Time
By default, calculations are relative to DateTime.utc_now(). You can specify a custom reference time:
reference = ~U[2026-06-15 10:00:00Z]
{:ok, dt} = Quando.parse("+7d", reference: reference)
# => ~U[2026-06-22 10:00:00Z]Week Start
By default, weeks start on Monday (1). You can specify a different start day:
# Week starts on Sunday
{:ok, dt} = Quando.parse("sow", week_start: 7)Key Disambiguation
Following Taskwarrior conventions:
m= months (not minutes)minormins= minutes
This matches CLI tools where quick typing is important and months are more commonly referenced than minutes for task scheduling.
Reference
License
MIT - see LICENSE