mmntjs
Compatibility-first migration bridge away from moment.js

Compatibility

Compatibility should be inspectable.

This page exists to show what matches moment.js, what is partial, what is unsupported, and where teams should read more before rollout.

How To Read This Page

The goal is not to make a sweeping claim that every behavior is identical in every context. The goal is to make the current state legible enough that a staff engineer or maintainer can decide whether a controlled evaluation is justified.

Current Evidence

  • 678/678 upstream moment.js compatibility tests passing
  • 4642/4642 hard-test suite passing in the current tracked baseline
  • 744/744 timezone compatibility cases passing across six timezones
  • 112 property-style oracle tests with tens of thousands of assertions against upstream moment.js
  • 9 coverage-guided fuzz harnesses plus a grammar-based ISO generator

Comparison Policy

  • Prefer documented scope over blanket claims.
  • Treat compatibility bugs as release-relevant changes, not as incidental cleanup.
  • Keep known differences visible enough that migration reviewers can use them directly.

In practice, that means a page like this should help a reviewer answer two questions: what behavior appears compatible enough to evaluate now, and where should we add targeted checks before widening scope?

Matrix

Area Status Notes
Parsing Mostly compatible Standard ISO, RFC 2822, custom format, array, object, sign-prefixed, and control-character inputs match moment.js. One known difference is mixed input like "93280531 09-3911".
Formatting Compatible Token and locale output are covered by upstream and locale-derived tests.
Manipulation Compatible add/subtract/startOf/endOf semantics are treated as compatibility-critical.
Query and comparison Compatible diff and comparison methods are covered by oracle and property tests.
Duration Compatible Construction, normalization, and relative-time behavior are part of the test matrix.
Locale Compatible Locale behavior is validated against the upstream locale suite.
UTC and parseZone Compatible UTC and fixed-offset behavior are tested; timezone package provides compatible IANA timezone data support.
Invalid dates Compatible Examples: moment("2024-02-31"), moment("not-a-date"), moment([2024, 1, 31]), and moment.invalid().

Status Vocabulary

  • Compatible: Behavior is expected to match within the documented scope and is covered by direct tests.
  • Mostly compatible: Behavior is broadly aligned, but some known edge cases remain and are documented.
  • Partial: Useful support exists, but adoption should be limited to the documented subset.
  • Not supported: Do not assume equivalent behavior without a dedicated compatibility layer.

Known Differences

  • Current known gaps are concentrated in specific parsing edge cases rather than broad API areas.
  • One concrete example is mixed input "93280531 09-3911".
  • Invalid-date and offset-sensitive behavior are documented explicitly because they drive migration risk.
  • Compatibility claims should always be read with the documented scope in mind.

Known Difference Highlights

This is intentionally plain language. The audience for this page is trying to assess adoption risk, not to decode whether caveats are being softened by marketing.

Highest-Risk Evaluation Areas

Parsing

Check the exact inputs your app already relies on: ISO strings, RFC 2822 mail dates, custom format strings, and array inputs like [2024, 0, 1]. One current known difference is mixed input like "93280531 09-3911".

Invalid dates

Examples: moment("2024-02-31"), moment("not-a-date"), moment([2024, 1, 31]), and moment.invalid(). Check how they behave in isValid(), format(), diff(), and comparisons.

Timezone and offsets

UTC and fixed-offset flows need explicit review around keepLocalTime, parseZone, and DST-adjacent transitions.

Parsing Edge Cases

One current known parsing-difference input is:

"93280531 09-3911"

Invalid Date Examples

Examples of invalid inputs and invalid values:

moment("2024-02-31").isValid() // false
moment.invalid().format() // "Invalid date"
moment("not-a-date").diff(moment("2024-01-01")) // invalid-path behavior should match moment.js

Unsupported Or Separate Scope

For most teams, this means the first migration question is not "is everything identical?" but "does the subset we rely on behave the same under our tests and fixtures?" This page is meant to support that narrower and more useful decision.