Skip to content

Date & Time Module

The date_time standard library module provides relational predicates for constructing, decomposing, and manipulating dates and times. All predicates work with real Python datetime objects — not custom term types.

The implementation lives in clausal/modules/date_time.py.


Import

-import_from(date_time, [Now, Today, Date, Time, DateTime,
                         TimeDelta, DateAdd, DateSub, DateDiff,
                         DaysBetween, FormatDate, ParseDate,
                         DateOf, DayOfWeek, DateBetween])

Or via module import:

-import_module(date_time)
# then use date_time.Now(...), date_time.Date(...), etc.

Python Interop

All predicates produce and consume standard Python objects:

Predicate Python type
Date/4 datetime.date
Time/4 datetime.time
DateTime/7 datetime.datetime
TimeDelta/3 datetime.timedelta

Unification uses Python's native ==. Any datetime method can be called via ++() interop:

-import_from(date_time, [Date, FormatDate])

IsoDate(Y, M, D, S) <- (
    Date(Y, M, D, DT),
    S is ++DT.isoformat()
)

Prefer the declarative predicates over ++ escapes

++() drops into arbitrary Python and is reserved for last-resort interop. The common date operations all have clean, relational equivalents — reach for these first:

Instead of ++ Use
S is ++DT.isoformat() FormatDate(DT, "%Y-%m-%d", S)
N is ++TD.days TimeDelta(N, _, TD)
D is ++DT.date() DateOf(DT, D)
DateDiff(A, B, TD), N is ++TD.days DaysBetween(A, B, N)

Predicates

Now/1, NowUTC/1, Today/1

Now(DT)        # DT = datetime.datetime.now()
NowUTC(DT)     # DT = datetime.datetime.now(UTC)
Today(D)       # D = datetime.date.today()

Date/4 — Bidirectional

Date(Year, Month, Day, DateObj) — construct or decompose:

# Construct
Date(2026, 3, 16, D)    # D = datetime.date(2026, 3, 16)

# Decompose
Date(Y, M, D, SomeDateObj)    # Y, M, D bound to components

Time/4 — Bidirectional

Time(Hour, Minute, Second, TimeObj):

Time(14, 30, 0, T)      # T = datetime.time(14, 30, 0)
Time(H, M, S, T)      # decompose T into components

DateTime/7 — Bidirectional

DateTime(Year, Month, Day, Hour, Minute, Second, DtObj):

DateTime(2026, 3, 16, 14, 30, 0, DT)
# DT = datetime.datetime(2026, 3, 16, 14, 30, 0)

TimeDelta/3 — Bidirectional

TimeDelta(Days, Seconds, TdObj):

TimeDelta(7, 0, TD)     # TD = datetime.timedelta(days=7)
TimeDelta(D, S, TD)    # decompose TD into days and seconds

DateAdd/3, DateSub/3

DateAdd(DATE, DELTA, RESULT)    # RESULT = DATE + DELTA
DateSub(DATE, DELTA, RESULT)    # RESULT = DATE - DELTA

DateDiff/3

DateDiff(D1, D2, TD)    # TD = D1 - D2 (timedelta)

DaysBetween/3

DaysBetween(DateA, DateB, N) — the whole-day count of DateA - DateB as a plain integer, so the common "days between two dates" need is a single goal instead of DateDiff(A, B, TD), TimeDelta(N, _, TD):

DaysBetween(A, B, N)    # N = (A - B).days (integer) — no DateDiff+decompose

FormatDate/3

FormatDate(DT, "%Y-%m-%d", S)    # S = "2026-03-16"

ParseDate/3

ParseDate("2026-03-16", "%Y-%m-%d", DT)    # DT = datetime.datetime(...)

DateOf/2 — Bidirectional

DateOf(DateTime, Date) — the declarative form of ++DT.date(). Forward, it extracts the calendar datetime.date from a datetime.datetime; in reverse (with DateTime unbound) it builds the midnight datetime of a datetime.date:

DateOf(DT, D)    # D = DT.date()        (datetime → date)
DateOf(DT, D)    # DT = midnight of D   (date → datetime; DT unbound)

DayOfWeek/2

DayOfWeek(D, DOW)    # DOW = 0 (Monday) through 6 (Sunday)

DateBetween/3 — Nondeterministic

DateBetween(Start, End, D) — generates each date in the range [Start, End]:

-import_from(date_time, [Date, DateBetween])

WeekDates(START, END, D) <- DateBetween(START, END, D)

This is nondeterministic — it succeeds once for each date in the range via backtracking.


Test coverage

Tests are in tests/test_date_time.py.

  • Now/NowUTC/Today: current timestamps
  • Date/4: construct, decompose, invalid values
  • Time/4: construct, decompose
  • DateTime/7: construct, decompose
  • TimeDelta/3: construct, decompose
  • DateAdd/DateSub/DateDiff: arithmetic
  • DaysBetween: direct integer day count
  • FormatDate/ParseDate: strftime/strptime
  • DateOf: datetime ↔ date (both modes)
  • DayOfWeek: weekday computation
  • DateBetween: date range enumeration

See also: I/O — writing and formatting output · Python Interop++() escape for additional datetime operations.