Skip to content

Date Fields and Date Calculations

pytaskwarrior accepts date strings for task fields. Returned dates are parsed into Python datetime objects on TaskOutputDTO.

Two backends, two date engines

The default TC adapter (TaskWarrior() with no task_cmd) resolves date strings via a pure-Python engine. It supports ISO 8601, the most common named synonyms (today, eom, eow, day names…), ISO durations, and compact relative expressions (now+3d, eom-1w).

The CLI adapter (TaskWarrior(task_cmd="task")) delegates to the task binary, which supports everything the TC adapter does plus month names (november), day ordinals (1st), later/someday, DOM-relative dates (due-7d), and many more extended synonyms. Expressions marked CLI-only in this page require task_cmd="task".


Date Fields

TaskInputDTO — input fields (strings)

Field Description
due Latest date by which the task must be completed
scheduled Earliest date the task can be started
wait Task is hidden from pending list until this date
until Task auto-deletes on this date (use with care)

All four fields accept the same date formats listed below. They are str | None.

from taskwarrior import TaskWarrior, TaskInputDTO

tw = TaskWarrior()

task = TaskInputDTO(
    description="Send birthday card to Alice",
    due="2026-11-08",
    scheduled="2026-11-04",   # earliest I can work on it
    wait="2026-11-01",        # hidden until November 1st (ISO — works with both adapters)
    until="2026-11-10",       # auto-deletes if not done by then
)
tw.add_task(task)

TaskOutputDTO — returned fields (datetime objects)

Field Description
due Due date as datetime \| None
scheduled Scheduled date as datetime \| None
wait Wait date as datetime \| None
until Until date as datetime \| None
entry Creation timestamp (read-only)
start When the task was started (read-only)
end When the task was completed or deleted (read-only)
modified Last modification timestamp (read-only)
task = tw.get_task(uuid)

if task.due:
    days_left = (task.due - datetime.now()).days
    print(f"Due in {days_left} days")

if task.scheduled and task.scheduled > datetime.now():
    print("Task is not yet ready to start")

Accepted Date Formats

ISO-8601

The most explicit format. Recommended for programmatic use.

task = TaskInputDTO(description="Meeting", due="2026-06-15")
task = TaskInputDTO(description="Meeting", due="2026-06-15T09:30:00")
task = TaskInputDTO(description="Meeting", due="2026-06-15T09:30:00+02:00")  # with timezone

Common ISO patterns:

Pattern Example Meaning
YYYY-MM-DD 2026-06-15 Date, time 00:00:00 local
YYYY-MM-DDThh:mm:ss 2026-06-15T09:30:00 Date + time, local
YYYY-MM-DDThh:mm:ssZ 2026-06-15T09:30:00Z Date + time, UTC
YYYY-MM-DDThh:mm:ss+hh:mm 2026-06-15T09:30:00+02:00 Date + time, with offset
YYYY-Www 2026-W24 First day of ISO week
YYYY-MM 2026-06 First day of month

Duration / Offset Expressions

TaskWarrior accepts ISO 8601 duration strings as relative offsets from now.

Expression Meaning
P1D 1 day from now
P1W 1 week from now
P2W 2 weeks from now
P1M 1 month from now
P1Y 1 year from now
PT2H 2 hours from now
P1DT4H 1 day and 4 hours from now
task = TaskInputDTO(description="Follow-up", due="P2W")     # due in 2 weeks
task = TaskInputDTO(description="Reminder", wait="P3D")     # hidden for 3 days

Named Synonyms

Human-friendly date names.

Supported by the default TC adapter

Relative days:

Synonym Meaning
now Current date and time
today / sod Today at 00:00:00
eod Today at 23:59:59
yesterday Yesterday at 00:00:00
tomorrow Tomorrow at 00:00:00

Days of the week — resolves to the next occurrence of that day:

task = TaskInputDTO(description="Weekly review", due="friday")
task = TaskInputDTO(description="Stand-up", due="monday")
# Full names or abbreviated: "mon", "tue", "wed", "thu", "fri", "sat", "sun"

Boundaries (subset):

Synonym Meaning
eow End of current week (Sun 23:59:59)
eom End of current month (23:59:59)
eoy End of current year (23:59:59)

Relative expressions (arithmetic on the above):

# TC adapter resolves these correctly
task = TaskInputDTO(description="Deadline", due="eom-1w")   # 1 week before end of month
task = TaskInputDTO(description="Follow-up", due="now+3d")  # 3 days from now
task = TaskInputDTO(description="Reminder", due="today+2w") # 2 weeks from today

CLI-only synonyms (require task_cmd="task")

The expressions below are resolved by the task binary and return None (silently ignored) when used with the default TC adapter. Use ISO 8601 dates instead, or switch to TaskWarrior(task_cmd="task").

Month / quarter / year boundaries:

Synonym Meaning
som / eom (already covered above)
sonm / eonm Start / end of next month
sopm / eopm Start / end of previous month
sow / eow (already covered above)
soww / eoww Start / end of current work week (Mon–Fri)
sonw / eonw Start / end of next week
sopw / eopw Start / end of previous week
soq / eoq Start / end of current quarter
sonq / eonq Start / end of next quarter
soy / sony / eony Start / end of current or next year

Month names — resolves to the 1st of the next month with that name (CLI-only):

# CLI-only — use ISO date with TC adapter
# WRONG with TC adapter:  task = TaskInputDTO(description="...", wait="november")
# CORRECT with TC adapter:
task = TaskInputDTO(description="Holiday prep", wait="2026-11-01")

Day ordinals — next occurrence of that day-of-month (CLI-only):

# CLI-only — use ISO date with TC adapter
# WRONG with TC adapter: task = TaskInputDTO(description="Pay rent", due="1st")
# CORRECT with TC adapter:
task = TaskInputDTO(description="Pay rent", due="2026-07-01")

next <weekday> (CLI-only):

# CLI-only — use the weekday name directly for "next occurrence":
# WRONG with TC adapter: due="next monday"
# CORRECT with TC adapter: due="monday"  (already means next occurrence)
task = TaskInputDTO(description="Review", due="monday")

Special:

Synonym Availability
later / someday CLI-only — far future (9999-12-30)
easter / goodfriday CLI-only

Relative Expressions (DOM-based) — CLI-only

Defining dates relative to other date fields (e.g. due-7d for scheduled) is evaluated by the task binary and is not supported by the TC adapter.

# CLI-only (requires task_cmd="task"):
task = TaskInputDTO(
    description="Project deliverable",
    due="2026-09-30",
    scheduled="due-7d",    # 1 week before due — CLI only
    wait="due-14d",        # 2 weeks before due — CLI only
    until="due+3d",        # 3 days after due — CLI only
)

# TC adapter equivalent — compute the dates in Python:
from datetime import date, timedelta
due = date(2026, 9, 30)
task = TaskInputDTO(
    description="Project deliverable",
    due=due.isoformat(),
    scheduled=(due - timedelta(weeks=1)).isoformat(),
    wait=(due - timedelta(weeks=2)).isoformat(),
    until=(due + timedelta(days=3)).isoformat(),
)
tw.add_task(task)

Note: Even with the CLI adapter, if you later change due, the other dates are not recalculated automatically. Update them explicitly with tw.modify_task(...).


task_calc() — Evaluating Date Expressions

Use task_calc() to resolve a date expression to an ISO datetime string.

TC adapter — resolves via pure Python (subset of expressions):

tw = TaskWarrior()

print(tw.task_calc("eom"))           # e.g. "2026-02-28T23:59:59"
print(tw.task_calc("friday"))        # e.g. "2026-03-06T00:00:00"
print(tw.task_calc("now+2w"))        # e.g. "2026-03-13T09:15:00"
print(tw.task_calc("P1M"))           # e.g. "2026-03-28T09:15:00"
print(tw.task_calc("2026-06-15 + 30d"))  # "2026-07-15T00:00:00"

Raises TaskWarriorError for unsupported expressions (month names, day ordinals, etc.).

CLI adapter — delegates to task calc, supports full range:

tw_cli = TaskWarrior(task_cmd="task")
print(tw_cli.task_calc("next monday"))  # supported in CLI mode
print(tw_cli.task_calc("november"))     # resolves to next Nov 1st

task_date_validator() — Validating Date Strings

Use task_date_validator() to check whether a string is a valid date expression.

tw.task_date_validator("2026-06-15")   # True  — valid ISO date
tw.task_date_validator("friday")       # True  — valid synonym
tw.task_date_validator("eom")          # True  — valid synonym
tw.task_date_validator("P2W")          # True  — valid ISO duration
tw.task_date_validator("now+3d")       # True  — valid relative
tw.task_date_validator("next monday")  # False — CLI-only, not supported by TC adapter
tw.task_date_validator("november")     # False — CLI-only
tw.task_date_validator("invalid-date") # False — not recognized

Typical use: validate user-supplied input before creating a task.

user_input = input("Due date: ")
if tw.task_date_validator(user_input):
    task = TaskInputDTO(description="Task", due=user_input)
    tw.add_task(task)
else:
    print(f"'{user_input}' is not a valid date expression.")

Filtering Tasks by Date

Use filter tokens in get_tasks(). The TC adapter supports field.before:, field.after:, field.by:, field.not: operators and virtual tags like +OVERDUE, +DUETODAY, +DUE, +SCHEDULED.

# Tasks due today (use virtual tag — not due:today which is CLI-only)
tw.get_tasks("+DUETODAY")

# Tasks due this week
tw.get_tasks("due.before:eow")

# Tasks due in the next 7 days
tw.get_tasks("due.before:now+7d")

# Overdue tasks
tw.get_tasks("+OVERDUE")

# Tasks with any due date (Python post-filter — due.any: not supported by TC adapter)
all_tasks = tw.get_tasks()
tasks_with_due = [t for t in all_tasks if t.due is not None]

# Tasks with no due date (Python post-filter)
tasks_without_due = [t for t in all_tasks if t.due is None]

# Tasks due in a specific month
tw.get_tasks("due.after:2026-03-01 due.before:2026-04-01")

CLI adapter supports the full filter syntax including due:today, due.any:, due.none:, and or/and boolean operators.


Semantic Summary of the Four Date Fields

Timeline ──────────────────────────────────────────────────────────►

  [wait] ──► task becomes visible
                [scheduled] ──► task becomes READY
                                      ... work on it ...
                                                    [due] ──► OVERDUE
                                                                  [until] ──► auto-DELETE
Field Task is hidden? Task is ready? Urgency effect
wait Yes, until date None while waiting
scheduled No Only after date Elevated when ready
due No Increases as deadline approaches
until No None (hard expiry)