Skip to content

feat(stdlib): add datetime module bindings#267

Merged
dbrattli merged 2 commits intomainfrom
repo-assist/bindings-datetime-2026-04-21-9acec82cb3409615
Apr 21, 2026
Merged

feat(stdlib): add datetime module bindings#267
dbrattli merged 2 commits intomainfrom
repo-assist/bindings-datetime-2026-04-21-9acec82cb3409615

Conversation

@github-actions
Copy link
Copy Markdown
Contributor

🤖 This is an automated pull request from Repo Assist, an AI assistant for this repository.

Summary

Adds F# bindings for Python's datetime module — one of the most-used modules in the stdlib and previously absent from Fable.Python.

Changes

New file: src/stdlib/Datetime.fs

Covers the five main classes:

Class Key features bound
timedelta days, seconds, microseconds, total_seconds() + keyword-argument factory
date year/month/day, isoformat(), strftime(), fromisoformat(), today(), fromtimestamp(), weekday(), replace()
time hour/minute/second/microsecond, isoformat(), strftime(), fromisoformat()
datetime Full date+time properties, now(), utcnow(), fromisoformat(), strptime(), combine(), timestamp(), isoformat(), astimezone(), replaceDate(), replaceTime()
timezone Fixed-offset factory, utc singleton

New file: test/TestDatetime.fs — 30 tests covering all bound classes.

Design Decisions

  • Each class has a separate static factory type (e.g. datetimeStatic) alongside the instance type (datetime). This mirrors the pattern in Functools.fs and Itertools.fs and keeps class methods separate from instance methods.
  • Constructor Emit templates wrap integer args with int(...) to handle Fable's Int32 boxing correctly.
  • timedelta.Create and time.Create use [<NamedParams>] + [<Emit("$0($1...)")>] so callers can write timedelta.Create(days = 2.0, hours = 3.0) idiomatically.
  • datetime.isoformat has two overloads: no-arg (default T separator) and a sep: string overload via [<Emit>].
  • replaceDate and replaceTime use named-keyword Emits to avoid the complex optional-parameter combinatorial explosion of Python's datetime.replace(...).
  • No breaking changes — this is a purely additive module.

Trade-offs

  • tzinfo (abstract base class) is not bound since it is rarely used directly by consumers; timezone covers the common use-case.
  • datetime.replace() is split into replaceDate and replaceTime helpers rather than a single method with many optional args; this avoids a complex overload matrix while covering the most common use-cases.
  • astimezone accepts obj for the tz parameter to avoid a circular dependency with timezone.

CI will validate the build and all 30 new tests.

Note

🔒 Integrity filter blocked 10 items

The following items were blocked because they don't meet the GitHub integrity level.

To allow these resources, lower min-integrity in your GitHub frontmatter:

tools:
  github:
    min-integrity: approved  # merged | approved | unapproved | none

Generated by Repo Assist · ● 2.3M ·

Adds F# bindings for the Python datetime module, covering:
- timedelta (duration with days/seconds/microseconds, total_seconds())
- date (year/month/day, isoformat, strftime, weekday, fromisoformat, replace)
- time (hour/minute/second/microsecond, isoformat, strftime, fromisoformat)
- datetime (full date+time, now, utcnow, fromisoformat, strptime, combine, timestamp, astimezone)
- timezone (fixed-offset tzinfo, utc singleton)

Each class has a separate static factory type (timedeltaStatic, dateStatic,
timeStatic, datetimeStatic, timezoneStatic) for constructors and class methods.
Int arguments use int($1) Emit wrappers to handle Fable's Int32 boxing.

Adds 30 tests covering all bound classes and their main operations.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@dbrattli dbrattli changed the title [Repo Assist] feat(stdlib): add datetime module bindings feat(stdlib): add datetime module bindings Apr 21, 2026
Datetime:
- Switch from paired static-factory types to Queue.fs-style primary-ctor
  classes. The original factory pattern combined [<Emit("$0($1...)")>] with
  [<NamedParams>], which silently dropped all kwargs (generated timedelta()
  instead of timedelta(days=3.0)).
- timedelta: empty primary ctor plus static ofDays/ofHours/ofMinutes/
  ofSeconds/ofWeeks/ofMilliseconds/ofMicroseconds factories with float()
  emit wrappers so Fable's Float64 doesn't reach Python's datetime. Added
  add/sub/neg arithmetic.
- timezone: moved above datetime so datetime.astimezone/now(tz)/
  fromtimestamp(tz) can take timezone instead of obj.
- date/time/datetime: collapsed replaceDate/replaceTime into a single
  [<NamedParams>] replace that supports partial replacement (any subset of
  fields). Added time.replace.
- datetime: arithmetic via sub(datetime)->timedelta, sub(timedelta)->
  datetime, add(timedelta)->datetime. utcnow marked [<Obsolete>] pointing
  at now(tz = timezone.utc).
- Module-level doc note about the `time` identifier collision with
  Fable.Python.Time.
- Tests expanded from 30 to 37 covering partial replace, arithmetic,
  datetime.now(tz), and the ofX factories.

justfile:
- Drop -r from `dotnet fantomas` invocations in `format` and `format-check`;
  fantomas has no -r flag and it caused both recipes to fail.

Other files: fantomas reformatting applied by `just format` to pre-existing
files touched by the formatter.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@dbrattli dbrattli marked this pull request as ready for review April 21, 2026 21:47
@dbrattli dbrattli merged commit db5f0b3 into main Apr 21, 2026
2 checks passed
@dbrattli dbrattli deleted the repo-assist/bindings-datetime-2026-04-21-9acec82cb3409615 branch April 21, 2026 21:50
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant