iamkun/dayjs
github.com/iamkun/dayjs ↗ · 375 files · 780 KB
English | 简体中文 | 日本語 | Português Brasileiro | 한국어 | Español (España) | Русский | Türkçe | සිංහල | עברית Fast 2kB alternative to Moment.js with the same modern API Day.js is a minimalist JavaScript library that parses, validates, manipulates, and displays dates
Overview
Day.js is a JavaScript date and time library for developers who want a chainable, largely Moment-compatible API with immutable operations by default. Its core wraps native Date objects, while separately loaded plugins add format parsing, durations, timezone conversion, calendar queries, and other capabilities. Locale modules supply translated names and formatting rules; the build produces a minified UMD library, separate plugin and locale bundles, ESM files, and TypeScript declarations.
System map
The runtime is a callable factory backed by one Dayjs class and shared locale state. Core date operations use native Date, constants, and a small utility module; plugins extend the same class and factory. Packaging separates the core from optional plugins and locales and supplies declarations for JavaScript consumers using TypeScript. GitHub Actions defines development checks and a separate master release pipeline.
- The package publishes dayjs.min.js as its main entry and index.d.ts as its declaration entry; the source factory is exported from src/index.js.
- src/index.js imports constants, English locale data, and utilities; module initialization registers English in Ls and selects it as the global locale.
- Dayjs owns a native Date in $d, cached year/month/day/time fields, a locale name in $L, and extension metadata in $x; construction invokes overridable parse and init methods.
- extend(plugin, option) passes the Dayjs class and factory to plugins and marks the plugin function with $i after installation; Ls and p expose shared locale and capability state.
- The timezone integration obtains offsets and names through host Intl.DateTimeFormat, while its implementation calls the separately supplied UTC API.
- build/index.js discovers locale files and plugin directories, emits separate bundles, builds the core, copies types to the package root, and creates locale.json; Rollup emits compact UMD with dayjs external.
- The babel script transpiles src into esm, then build/esm.js adjusts locale imports and relocates plugin declarations; .npmignore excludes source, tests, tooling, and original types from publication.
- Development pushes and PRs invoke reusable lint/test CI; master pushes gate release on that workflow, then build UMD/ESM, audit signatures, and invoke semantic-release.
Feature catalog
The public surface centers on parsing, immutable manipulation, comparison, formatting, and serialization. Optional modules broaden input types, calendar calculations, translated output, timezone handling, and duration arithmetic. Compatibility plugins add aliases or deliberately change mutation behavior. The following eight groups cover the inspected core and plugin APIs; these are library capabilities rather than application screens or routes.
- Core APIs construct and validate dates, clone, get/set calendar fields, add/subtract units, compute boundaries and differences, compare dates, count month days, and output formatted strings, epoch values, native Dates, JSON, ISO, and UTC strings.
- customParseFormat accepts format strings, ordered format alternatives, locale arguments, strict round-trip validation, and a configurable two-digit-year parser; arraySupport, objectSupport, bigIntSupport, and negativeYear adapt additional inputs.
- Formatting supports bracket literals and locale names; advancedFormat adds quarter, ordinal, week/year, timestamp, 24-hour, and zone-name tokens, localizedFormat expands L/LT families, and buddhistEra adds BB/BBBB with a 543-year bias.
- Locales can be selected globally or per instance; localeData exposes month/weekday lists and rules, updateLocale merges configuration, preParsePostFormat transforms input/output, relativeTime adds from/to/fromNow/toNow, and calendar chooses contextual date labels.
- Calendar plugins provide dayOfYear, quarter getters/setters and arithmetic, locale-relative weekday/week/weekYear, ISO weekday/week/weekYear and boundaries, leap-year detection, and ISO weeks-in-year counting; several call companion plugin methods.
- Query plugins add inclusive comparisons, isBetween with configurable endpoint inclusion and reversed-bound support, isToday/isTomorrow/isYesterday by formatted calendar date, and min/max selection that propagates encountered invalid dates.
- utc adds UTC construction, local/UTC conversion, explicit offsets, and isUTC; timezone adds named-zone construction/conversion, keepLocalTime, offsetName, host-zone guessing, and a default zone for tz calls.
- duration supplies numeric/object/ISO duration inputs, component and total-unit getters, arithmetic, formatting, serialization, humanization, and date arithmetic; toArray/toObject export fields, pluralGetSet adds aliases, isMoment aliases isDayjs, badMutable enables mutation, and devHelper emits development diagnostics.src/plugin/duration/index.js#L60-L107src/plugin/duration/index.js#L188-L257src/plugin/duration/index.js#L261-L295src/plugin/toArray/index.js#L3-L12src/plugin/toObject/index.js#L3-L12src/plugin/pluralGetSet/index.js#L4-L19src/plugin/isMoment/index.js#L1-L4src/plugin/badMutable/index.js#L3-L30src/plugin/devHelper/index.js#L4-L37
Data flow
Inputs pass through the factory and an overridable parsing boundary into native Date state. Cached fields drive most calendar operations and display, while valueOf provides the epoch boundary for comparisons and elapsed-time calculations. Clones retain locale and extension metadata, and optional plugins reinterpret parsing, offsets, or output. Serialization returns values to the caller; the inspected runtime does not implement durable persistence.
- dayjs(date, c) clones recognized Dayjs inputs; otherwise it reuses an object configuration or creates one, attaches date and original arguments, and passes it to new Dayjs.
- parseDate maps null to an invalid Date, undefined to now, and Date objects to copies; matching non-Z strings become local or UTC components with milliseconds truncated to three digits, while other inputs use native Date parsing.
- parse stores the Date and invokes init to cache calendar fields; wrapper propagates $L, $u, $x, and $offset into new instances, and clone uses that wrapper.
- set clones before $set; month/year changes temporarily move to day 1 and clamp the original day, while add branches between calendar changes for months/years/days/weeks and timestamp increments for smaller units.
- format resolves the instance's current registry locale, rejects invalid state with a locale-specific message or Invalid Date, and replaces recognized tokens while preserving bracket literals.
- customParseFormat tokenizes a format into regex/parser entries, accumulates fields, corrects meridiem hours, constructs a Date with defaults and offset handling, then optionally invalidates a nonmatching strict round trip.
- Named-zone string parsing converts wall-clock fields through UTC, reconciles an offset guess against Intl-derived offsets, and stores the result in $offset and $x.$timezone; UTC valueOf subtracts offset bookkeeping to recover the instant.
- toDate creates a fresh Date from valueOf; toJSON emits ISO for valid dates and null for invalid dates. Duration JSON instead emits an ISO duration string, and named-zone/locale metadata is not included in these outputs.
Behavior traces
Eight traces follow concrete public operations through their implementation branches. They cover initial construction, calendar manipulation, locale registration, strict parsing, timezone parsing/conversion, durations, and serialization. Each trace describes source execution order rather than an observed runtime result. Persistence here is the caller-facing serialization boundary.
- Construction: module initialization loads English → dayjs('2024-03-20') attaches configuration → Dayjs constructor selects $L → parse calls parseDate → init caches local fields → constructor assigns $x and the Dayjs marker.
- Month arithmetic/display: dayjs('2024-01-31').add(1, 'month') → prettyUnit → set → clone → $set moves to day 1 and clamps to destination daysInMonth → init → format replaces YYYY/MM/DD tokens; the core setter leaves the original date intact.
- Locale display: importing zh-cn calls dayjs.locale(locale, null, true) → parseLocale registers the object without selecting it globally → instance.locale('zh-cn') clones and changes $L → format reads translated month/day/meridiem data.
- Strict parsing: extend(customParseFormat) installs its parse wrapper → dayjs(input, format, true) preserves arguments → parseFormattedInput calls makeParser and constructs a Date → init → format(format) comparison invalidates mismatches; format arrays recursively try candidates until one is valid.
- Named-zone construction: with UTC installed, dayjs.tz(string, zone) → tzOffset(now, zone) chooses an initial offset → dayjs.utc(string, optionalFormat).valueOf() obtains wall-clock fields → fixOffset reconciles guesses or a DST gap → dayjs(targetTs).utcOffset(targetOffset) → stores $timezone; invalid parsed input returns an invalid instance.
- Zone conversion: instance.tz(zone, keepLocalTime) returns immediately for invalid state → toDate → toLocaleString and tzOffset → UTC conversion for zero offset or localized reconstruction otherwise → restore milliseconds and set offset → optionally add oldOffset-newOffset → attach $timezone.
- Duration arithmetic: dayjs.duration(object) captures the global locale → Duration normalizes component keys and calculates $ms → date.add(duration) detects Duration → manipulateDuration applies years, months, days, hours, minutes, seconds, and milliseconds in order; humanize separately calls fromNow and therefore needs relativeTime.
- Serialization: JSON.stringify(instance) reaches toJSON → isValid → toISOString for valid state or null otherwise; UTC overrides toISOString to use toDate, which calls offset-adjusted valueOf before native ISO serialization.
Testing signals
Tests and CI were inspected, not executed; no passing result or measured coverage is asserted. Jest covers core and plugin behavior, frequently comparing against Moment and using MockDate to control time. The npm test script runs explicit host-timezone matrices before requesting full line coverage. Browser and declaration checks have narrower scopes, and this inventory is bounded rather than exhaustive coverage.
- package.json configures Jest 22 with test roots under test, a *.test.js regex, and src-wide coverage collection; npm test requests a global 100% line threshold, whose satisfaction was not verified.
- Core parsing tests compare now, accepted string forms, timestamps, invalid inputs, millisecond truncation, and clone behavior against Moment; manipulation tests cover locale weeks, unit aliases, month-end/leap-day additions, and fractional days/weeks.
- customParseFormat tests distinguish permissive parsing from strict rejection of zero or overflowing fields and cover ordered alternatives, all-invalid arrays, and locale-aware strict parsing.
- Timezone tests assert formatted output, valueOf, and offsets against moment-timezone, including spring gaps, host/target DST desynchronization, overlap instants, Lord Howe transitions, quarter-hour zones, and invalid-date nonthrowing behavior.
- npm test runs core timezone tests in Auckland, London, Whitehorse, and the default environment, then plugin timezone tests in Paris, London, New York, and Auckland; a test comment explicitly defers broader startOf/set/add calendar arithmetic.
- Separate issue2027 suites install duration/objectSupport in both orders and assert duration and numeric arithmetic, object/string parsing, and setters; the generic plugin test checks prototype APIs, factory APIs, options, and utility access.
- Locale key tests dynamically load locales and validate naming, header comments, arrays/functions, formats, and relative-time keys; plugin declaration tests only check that matching .d.ts files exist, without compiling them.
- Reusable CI invokes lint and npm test with optional Codecov upload. Separately configured Karma/Jasmine Sauce tests load the built core and test window installation, a chain, and nonstandard strings; that browser command is not invoked by the inspected reusable CI workflow.
Risk map
These are source observations and explicitly identified hypotheses, not confirmed vulnerabilities. The inspected runtime paths principally expose parsing and shared extension state; filesystem mutation and release credentials appear in tooling boundaries. Calendar correctness depends on native Date, Intl data, offset bookkeeping, and plugin composition. Existing regression tests constrain some of these behaviors but were not run.
- Input validation differs by mode: core isValid only checks native invalid-Date state, native component construction can normalize overflow, and customParseFormat rejects round-trip mismatches only when strict mode is requested.
- Plugins execute directly with the shared class and factory and can replace methods globally; badMutable intentionally removes clone-before-set behavior, while advancedFormat and duration call APIs supplied by companion plugins.
- Locale data is shared mutable state: instances resolve $L through Ls at call time, and updateLocale changes registry objects. Hypothesis: runtime locale updates can change output from already-created instances and require application-level coordination. (inferred)
- DST overlap resolution starts with the target zone's offset at the current time, and fixOffset documents that the guess selects ambiguous offsets; broader timezone calendar arithmetic is explicitly deferred in the test source.
- Timezone formatting constructs Intl.DateTimeFormat with caller-supplied zone names and caches by zone/name style without a local eviction or exception handler; invalid-date guards do not validate the zone identifier.
- Duration total-unit conversion assumes 365 days per year and one twelfth of that per month, whereas applying a duration to a date performs calendar-unit additions; consumers must distinguish fixed totals from calendar arithmetic.
- Build tooling writes package artifacts and unlinks relocated declarations; ESM paths partly depend on process.env.PWD. Core build and locale.json writes are not awaited, ESM uses async forEach callbacks, and outer catches log errors without explicitly setting a failing exit code.
- The release job inherits secrets, grants repository write and OIDC permissions, exposes GITHUB_TOKEN to release tooling, and installs additional release packages without saving them; it is a privileged boundary triggered by master pushes.
Extension points
The main extension contract is a plugin function that can modify the class, factory, and shared utilities. Locale objects supply data and callbacks independently of the core bundle. TypeScript declarations extend public interfaces separately from implementation. Build discovery automatically packages conventionally placed modules, making file naming and registration conventions part of the extension surface.
- New plugins implement (option, DayjsClass, dayjsFactory), install through dayjs.extend, and can add instance or factory methods; installation is guarded by the plugin function's $i marker.
- Existing-method extensions capture the previous implementation and delegate with the current instance; localizedFormat wraps format, UTC wraps parse/init, and isoWeek intercepts startOf only for its unit.
- $utils exposes shared helpers under short keys; the core adds locale resolution, Dayjs recognition, and metadata-preserving wrapper functions to the imported utility object.
- Locale modules register named objects with dayjs.locale(locale, null, true); supported hooks include ordinal, meridiem, relative-time functions, and preparse/postformat callbacks.
- Plugin options expose targeted customization: customParseFormat accepts parseTwoDigitYear, relativeTime accepts thresholds and rounding, and calendar accepts per-call format strings or functions.
- customParseFormat's expressions table maps tokens to regex/parser pairs, while formattingTokens determines token recognition; new parsing tokens must fit both stages.
- Type declarations support module augmentation of Dayjs and factory APIs, and ConfigType derives from the augmentable ConfigTypeMap; timezone and duration declarations demonstrate overloaded plugin surfaces.
- Build discovery expects locale files and src/plugin/<name>/index modules, generates matching distribution names, and copies declarations; locale metadata extraction requires the identifying '// Name [code]' comment.
Contributor handoff
Begin with the factory, utilities, constants, and the implementation/declaration/test trio for the target API. Preserve immutable defaults, calendar-versus-elapsed arithmetic, and plugin delegation order. Tests and CI were inspected, not executed, and any later validation must distinguish configured checks from observed results. This brief is a bounded source investigation; it neither establishes exhaustive coverage nor authorizes build, installation, or release actions.
- For core changes, read dayjs construction, parseDate, init, wrapper, and prettyUnit first; these determine accepted inputs, cached state, metadata propagation, and case-sensitive shorthand such as M versus m.
- Preserve ES6 and the repository's ESLint conventions: no statement semicolons or trailing commas, extensionless imports, and existing allowance for parameter reassignment; CONTRIBUTING recommends lint and semantic commit messages.
- Keep default immutability and month-end clamping intact; regression cases already compare January 31 month changes and leap-day year changes with Moment, while badMutable deliberately has different semantics.
- Before changing plugin composition, inspect both issue2027 installation-order suites and the captured old-method chains; a plugin's $i marker prevents installing that same function again with different options.
- Treat timezone and UTC as one edit boundary: tests install UTC first, offset-adjusted valueOf governs instant identity, and regression cases separate host DST from target DST. Do not extrapolate conversion coverage to all calendar arithmetic.
- Update matching declarations for public API changes and preserve locale header/name conventions; declaration tests check existence only, and runtime locale callbacks can be richer than the string-only relativeTime declaration fields.
- Under a later execution-authorized task, start with test-tz or test-tz-plugin for timezone changes, then broaden to npm test and lint; distribution changes also have build/babel and size checks. None of these commands was executed during this investigation.
- Edit source and declaration inputs rather than generated distribution files, inspect build filesystem operations before running them, and use README/source/tests for local onboarding because the English detailed docs are relocation notices; publishing is controlled by the separate master release workflow.
Languages
| Language | Files | Share of source |
|---|---|---|
| JavaScript | 283 | 88% |
| TypeScript | 40 | 12% |
| Markdown | 39 | docs/config |
| YAML | 4 | docs/config |
| JSON | 2 | docs/config |
Start reading here
Probable source entrypoint: src/ — inferred from the directory tree and manifest, not the upstream docs.
Source roots
src/ (184 files)
Source layout — src/
| Path | Files |
|---|---|
src/locale/ | 143 |
src/plugin/ | 19 |
Repository structure
| Top-level path | Files |
|---|---|
src/ | 184 |
test/ | 95 |
types/ | 40 |
docs/ | 37 |
.github/ | 5 |
patches/ | 1 |
Docs found: CONTRIBUTING.mdREADME.mddocs/en/API-reference.mddocs/en/I18n.mddocs/en/Installation.mddocs/en/Plugin.mddocs/es-es/API-reference.mddocs/es-es/I18n.mddocs/es-es/Installation.mddocs/es-es/Plugin.md
Package
package.json — dayjs v0.0.0-development, 30 declared dependencies.
@babel/cli@babel/core@babel/node@babel/preset-env@semantic-release/githubbabel-corebabel-jestbabel-plugin-external-helperscross-enveslinteslint-config-airbnb-baseeslint-plugin-import
CI & config entrypoints
README.md— Repository readme.github/workflows/release.yml— GitHub Actions workflow.github/workflows/check.yml— GitHub Actions workflow.github/workflows/lint-test.yml— GitHub Actions workflowpackage.json— npm scripts: babel, build, lint, prettier, sauce, size, test, test-tz
Structural health signals
Average score 8.6/10 across 96 analyzed source files; 0 hotspots surfaced.
src/index.js— 467 lines, score 6.7 (Large file, Long function/block)test/plugin/isBetween.test.js— 688 lines, score 7.4 (Large file, High churn)test/plugin/timezone.test.js— 583 lines, score 7.4 (Large file, High churn)
These are deterministic review leads — size, churn, and structural signals — not proof of a bug in this project.
Recent history
436bde0bcded2026-09-15 — chore: update doc6f0a430ebdb82026-09-15 — chore: update doc7c6b632c1ffe2026-09-15 — chore: update doc539c4b9446982026-09-09 — chore: update doc73017be414312026-09-01 — chore: update doc