dayjs
>=1.10.0 <2.0.0postconditions8functions7last verified2026-06-24coverage score100%Postconditions: what we check
- dayjs · dayjs-invalid-dateerrorWheninput string is not a valid date formatRequired 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 datavisibilitysilentSources[1]
- utc · utc-invalid-dateerrorWheninput string is not a valid date formatRequired 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 datavisibilitysilentSources[2]
- format · format-string-redoswarningWhenformat string is user-controlled or very longRequired 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 unavailablevisibilityvisibleSources[3]
- tz · tz-invalid-timezone-range-errorerrorWhentimezone string is not a valid IANA timezone identifierThrows
RangeError: 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 - tz · tz-setdefault-invalid-timezonewarningWhendayjs.tz.setDefault() called with invalid IANA timezone stringThrows
RangeError propagated on next dayjs.tz() callRequired 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 unavailablevisibilitysilentSources[4] - toISOString · toisostring-invalid-date-throwserrorWhencalled on a Day.js object created from an invalid date string or nullThrows
RangeError: 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 unavailablevisibilityvisibleSources[6] - humanize · humanize-missing-relativetime-pluginerrorWhenDuration.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.Throws
TypeError: dayjs(...).fromNow is not a functionRequired 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 - duration · duration-invalid-iso-string-silent-zerowarningWhenISO 8601 duration string is malformed or does not match the expected formatRequired 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
Every postcondition cites at least one of these. Grouped by source type; numbered to match the footnotes above.
- [1]day.js.org/docs/en/parseString
- [2]day.js.org/docs/en/pluginUtc
- [4]day.js.org/docs/en/pluginTimezone
- [5]developer.mozilla.org/en-US/docs/WebDateTimeFormat
- [6]developer.mozilla.org/en-US/docs/WebToISOString
- [7]day.js.org/docs/en/durationsHumanize
- [8]day.js.org/docs/en/pluginRelative Time
- [9]day.js.org/docs/en/pluginDuration
- [10]en.wikipedia.org/wiki/ISO_8601ISO 8601
- [3]github.com/iamkun/dayjs/pulliamkun/dayjs PR #2908
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
-
Main Documentation: https://day.js.org/docs/en/installation/installation
- "Day.js creates a wrapper for the Date object"
- "The Day.js object is immutable"
- Emphasizes browser and Node.js compatibility
-
Parsing Strings: https://day.js.org/docs/en/parse/string
- Documents that dayjs() can return invalid objects
- Invalid dates do not throw errors
- Must use isValid() to check
-
UTC Plugin: https://day.js.org/docs/en/plugin/utc
- UTC parsing behaves the same way
- Returns invalid object on bad input
-
Validation: https://day.js.org/docs/en/parse/is-valid
- isValid() returns boolean indicating if date is valid
- Invalid objects are created for bad input
- Non-strict mode: Only checks if parseable (dayjs('2022-01-33').isValid() returns true)
- Strict mode: Validates exact format (requires CustomParseFormat plugin)
- Quote: "This returns a boolean indicating whether the Dayjs's date is valid"
-
Plugin System: https://day.js.org/docs/en/plugin/plugin
- "A plugin is an independent module that can be added to Day.js"
- Loaded via dayjs.extend()
- 36+ built-in plugins available
-
Format Method: https://day.js.org/docs/en/display/format
- "Get the formatted date according to the string of tokens passed in"
- No error handling documentation for invalid format strings
NPM Package
- Package Page: https://www.npmjs.com/package/dayjs
- Installation and basic usage
- 2KB immutable date library
Repository
- GitHub: https://github.com/iamkun/dayjs
- Source code and documentation
- Modern alternative to moment.js
- 17M+ weekly downloads
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
-
Issue #320: https://github.com/iamkun/dayjs/issues/320
- "Validation .isValid() doesn't work always"
- Edge cases where invalid dates return isValid() = true
-
Issue #1238: https://github.com/iamkun/dayjs/issues/1238
- "Invalid dates are parsed as valid"
- Example: dayjs('2022-01-33') parses to 2022-02-02
-
Issue #2498: https://github.com/iamkun/dayjs/issues/2498
- "[isValid] function not works properly"
- Day overflow issues (Feb 31 → Mar 3)
-
Real-World Violation - TypeORM: https://github.com/typeorm/typeorm/blob/master/src/util/DateUtils.ts
- TypeORM's DateUtils.mixedDateToDate() method (lines 64-102)
- Calls dayjs(mixedDate).toDate() without .isValid() check
- Allows Invalid Date objects to propagate silently through ORM
- Impact: Data corruption, NaN timestamps in database
- Affects major library with 34,000+ stars and millions of users
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:
constant.jsline 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/glocalizedFormat/utils.jsline 3:/(\[\[^\]]+\])|(MMMM|MM|DD|dddd)/glocalizedFormat/utils.jsline 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:
- Pull Request: https://github.com/iamkun/dayjs/pull/2908
- OWASP ReDoS: https://owasp.org/www-community/attacks/Regular_expression_Denial_of_Service_-_ReDoS
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:
- Documentation: Educates developers about .isValid() requirement
- Detection: Catches real violations (validated with TypeORM case)
- Security: Warns about ReDoS in format strings
- Best Practices: Promotes strict parsing and input validation
Postconditions:
- invalid-date (ERROR): Missing .isValid() checks
- 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