Profiles·Public

dayjs

semver>=1.10.0 <2.0.0postconditions8functions7last verified2026-06-24coverage score100%

Postconditions: what we check

  • dayjs · dayjs-invalid-date
    error
    Wheninput string is not a valid date format
    Required handlingCaller MUST check isValid() before using the Day.js object. Invalid Day.js objects can cause incorrect date calculations, display issues, or NaN values propagating through the application. Use pattern: const d = dayjs(input); if (!d.isValid()) { /* handle error */ }
    costmediumin proddegraded serviceusers seelost datavisibilitysilent
    Sources[1]
  • utc · utc-invalid-date
    error
    Wheninput string is not a valid date format
    Required handlingCaller MUST check isValid() after parsing. Invalid UTC dates can cause timezone calculation errors and data corruption. Use pattern: const d = dayjs.utc(input); if (!d.isValid()) { /* handle error */ }
    costmediumin proddegraded serviceusers seelost datavisibilitysilent
    Sources[2]
  • format · format-string-redos
    warning
    Whenformat string is user-controlled or very long
    Required handlingAvoid using user-controlled format strings directly. Vulnerable regex patterns in format parsing can cause quadratic time complexity, leading to CPU exhaustion and DoS. Validate and limit format string length. See GitHub PR #2908 for technical details.
    costmediumin prodimmediate exceptionusers seeservice unavailablevisibilityvisible
    Sources[3]
  • tz · tz-invalid-timezone-range-error
    error
    Whentimezone string is not a valid IANA timezone identifier
    ThrowsRangeError: Invalid time zone specified: <timezone>
    Required handlingCallers MUST wrap dayjs.tz() and Dayjs.tz() calls in try-catch when the timezone value comes from user input, database values, or external APIs. Valid IANA identifiers include "America/New_York", "UTC", "Europe/London". Invalid identifiers like "EST", "PST", or misspelled names throw RangeError. Use a validation step: check against Intl.supportedValuesOf('timeZone') or wrap in try-catch. Unlike other Day.js operations, this is a REAL exception, not a silent invalidity. Pattern: try { const d = dayjs.tz(input, timezone); } catch (e) { if (e instanceof RangeError) { /* invalid timezone */ } }
    costmediumin prodimmediate exceptionusers seeservice unavailablevisibilityvisible
    Sources[4][5]
  • tz · tz-setdefault-invalid-timezone
    warning
    Whendayjs.tz.setDefault() called with invalid IANA timezone string
    ThrowsRangeError propagated on next dayjs.tz() call
    Required handlingWhen setting a default timezone via dayjs.tz.setDefault(timezone), the timezone string is NOT validated at call time. The RangeError is thrown lazily on the next dayjs.tz() call that uses the default timezone. This makes the failure delayed and harder to trace. Validate the timezone before calling setDefault(): const isValid = (tz: string) => { try { Intl.DateTimeFormat(undefined, { timeZone: tz }); return true; } catch { return false; } }; if (isValid(tz)) { dayjs.tz.setDefault(tz); }
    costmediumin proddegraded serviceusers seeservice unavailablevisibilitysilent
    Sources[4]
  • toISOString · toisostring-invalid-date-throws
    error
    Whencalled on a Day.js object created from an invalid date string or null
    ThrowsRangeError: Invalid time value (thrown by native Date.prototype.toISOString)
    Required handlingCallers MUST ensure the Day.js object is valid before calling toISOString(). Always call isValid() first, or use toJSON() (which returns null for invalid dates instead of throwing). Common pattern: const iso = d.isValid() ? d.toISOString() : null; Or use toJSON() as a safe alternative: const iso = d.toJSON(); This is particularly dangerous when dayjs() parses user-supplied date strings — invalid input propagates silently until toISOString() is called and throws.
    costmediumin prodimmediate exceptionusers seeservice unavailablevisibilityvisible
    Sources[6]
  • humanize · humanize-missing-relativetime-plugin
    error
    WhenDuration.humanize() called when only the duration plugin has been loaded via dayjs.extend(duration). The relativeTime plugin must also be extended before humanize() can succeed.
    ThrowsTypeError: dayjs(...).fromNow is not a function
    Required handlingAlways extend BOTH the duration plugin AND the relativeTime plugin before calling Duration.humanize(). The Day.js docs document this dependency but the dependency is not enforced at extend() time, so the error only surfaces on first humanize() call at runtime. Correct pattern: import dayjs from 'dayjs'; import duration from 'dayjs/plugin/duration'; import relativeTime from 'dayjs/plugin/relativeTime'; dayjs.extend(duration); dayjs.extend(relativeTime); dayjs.duration(60000).humanize(); Alternatively, wrap humanize() calls in try-catch when the plugin load order is dynamic or controlled by external code.
    costlowin prodimmediate exceptionusers seeservice unavailablevisibilityvisible
    Sources[7][8]
  • duration · duration-invalid-iso-string-silent-zero
    warning
    WhenISO 8601 duration string is malformed or does not match the expected format
    Required handlingCallers MUST validate ISO 8601 duration strings before passing to dayjs.duration(). Test the duration after creation: const d = dayjs.duration(str); if (d.asMilliseconds() === 0 && str !== 'P0D' && str !== 'PT0S') { /* invalid */ } Better: pre-validate with the ISO 8601 duration regex before calling duration(). Common invalid strings that silently produce zero-duration: - "1h30m" (not ISO format — should be "PT1H30M") - "1 day" (natural language — should be "P1D") - "90 minutes" (should be "PT90M") - "" (empty string) - "P" (bare P with no values)
    costmediumin proddegraded serviceusers seelost datavisibilitysilent
    Sources[9][10]

Sources

Every postcondition cites at least one of these. Grouped by source type; numbered to match the footnotes above.

Official documentation
Issues & pull requests

Research notes

Curator notes from SOURCES.md captured when the profile was written so you can verify the reasoning, not just the rules.

Sources: dayjs

Package: dayjs Contract Version: 1.0.0 Last Verified: 2026-02-26


Primary Sources

Official Documentation

NPM Package

Repository

Security

  • Snyk Security Database: https://security.snyk.io/package/npm/dayjs

    • No assigned CVEs in database (as of 2026-02-27)
    • 21M+ weekly downloads
    • Latest version: 1.11.19
    • Active maintenance with regular releases
  • ReDoS Vulnerability (Unfixed): https://github.com/iamkun/dayjs/pull/2908

    • Regular Expression Denial of Service in format parsing
    • Affects all versions (PR open but not merged as of 2026-02-27)
    • Quadratic time complexity with large format strings
    • Performance impact: ~100k chars → several seconds runtime
    • Severity: Medium-High (DoS via CPU exhaustion)
    • Attack vector: User-controlled format strings
    • Mitigation: Limit format string length, sanitize user input

Real-World Usage & Issues


Behavioral Claims

Invalid Date Parsing Returns Invalid Object

Claim: dayjs() and dayjs.utc() return invalid Day.js objects for bad input instead of throwing.

Evidence:

  • Documentation states invalid input creates invalid objects
  • isValid() method exists to check validity
  • API is intentionally compatible with moment.js
  • Source: https://day.js.org/docs/en/parse/

Severity: Error (invalid dates cause calculation errors and data corruption)

Known Limitation: Permissive Parsing

Claim: Day.js uses JavaScript's Date constructor which is very permissive.

Evidence:

  • GitHub Issue #320: ".isValid() doesn't work always"
  • GitHub Issue #1238: "Invalid dates are parsed as valid"
  • Example: dayjs('2022-01-33') returns isValid() = true but parses to 2022-02-02
  • Day overflow: Feb 31 becomes Mar 3
  • Source: https://github.com/iamkun/dayjs/issues/1238

Impact: Developers cannot rely solely on .isValid() for strict validation.

Recommendation: Use strict mode with CustomParseFormat plugin for critical date validation.


CVE Analysis

Result: 1 vulnerability found (no CVE assigned yet)

CVE-PENDING: ReDoS in Format Parsing

Type: Regular Expression Denial of Service (ReDoS) Status: UNFIXED (PR #2908 open since 2024, not merged as of 2026-02-27) Severity: Medium-High Affected Versions: All versions (<=1.11.x)

Vulnerable Regex Patterns:

  1. constant.js line 30: /\[([^\]]+)\]|Y{1,4}|M{1,4}|D{1,2}|d{1,4}|H{1,2}|h{1,2}|a|A|m{1,2}|s{1,2}|Z{1,2}|SSS/g
  2. localizedFormat/utils.js line 3: /(\[\[^\]]+\])|(MMMM|MM|DD|dddd)/g
  3. localizedFormat/utils.js line 14: /(\[\[^\]]+\])|(LTS?|l{1,4}|L{1,4})/g

Performance Impact:

  • Quadratic time complexity O(n²) with input size
  • At ~100,000 characters: several seconds runtime
  • LocalizedFormat tests: >10 seconds execution time

Attack Vector:

  • User-controlled format strings passed to .format()
  • Large or malformed format strings cause CPU exhaustion
  • Application freeze/DoS

Mitigation:

  • Limit format string length from user input
  • Sanitize format strings before use
  • Set timeouts for date parsing operations
  • Monitor PR #2908 for fix status

References:


Other Searches:

  • Snyk Security Database: No assigned CVEs
  • GitHub Security Advisories: No advisories
  • NVD/CVE Database: No entries

Note: A separate malicious package @realty-front/dayjs exists but is unrelated to the official dayjs package.


Notes

  • Day.js is designed as a moment.js replacement
  • Much smaller (2KB vs 16KB for moment)
  • Immutable objects (unlike moment)
  • Same error pattern as moment: returns invalid object instead of throwing
  • Plugin-based architecture for extended functionality
  • Does NOT throw exceptions - uses validation pattern instead
  • Primarily synchronous operations
  • 17M+ weekly downloads on npm
  • No security vulnerabilities found
  • Active maintenance (latest: 1.11.19 as of Feb 2026)

Contract Status

Current: production (v1.1.0) Last Updated: 2026-02-27 Priority: Medium (upgraded from Low due to ReDoS finding)

Contract Effectiveness:

  • Detection Rate: ~80% (based on fixture testing)
  • Real-World Validation: 1 violation found in TypeORM (true positive)
  • False Positive Rate: ~20% (acceptable for validation pattern)

Why This Contract Works: While dayjs doesn't throw exceptions (uses validation pattern), the analyzer can detect:

  • Missing .isValid() checks after dayjs() calls
  • Direct .toDate() conversions without validation
  • Pattern: dayjs(input).method() without .isValid() between

Contract Value:

  1. Documentation: Educates developers about .isValid() requirement
  2. Detection: Catches real violations (validated with TypeORM case)
  3. Security: Warns about ReDoS in format strings
  4. Best Practices: Promotes strict parsing and input validation

Postconditions:

  1. invalid-date (ERROR): Missing .isValid() checks
  2. format-string-redos (WARNING): User-controlled format strings

Validation Results:

  • Fixture testing: 80% detection rate (24 violations in 120 calls)
  • Real-world (TypeORM): 1 critical violation found
  • CVE research: 1 ReDoS vulnerability documented
Need a different package?
Request a profile