Profiles·Public

date-fns

semver>=3.0.0 <5.0.0postconditions22functions16last verified2026-04-20coverage score100%

Postconditions — what we check

  • parse · parse-returns-invalid-date
    warning
    WhenInput string is malformed, empty, or does not match the format string. parse() does NOT throw in this case — it returns an Invalid Date object (isNaN(date.getTime()) === true). Common mistakes: calling parse without isValid() check, passing the result to format() which WILL throw on Invalid Date.
    ReturnsInvalid Date object (isNaN(date.getTime()) is true)
    Required handlingAlways check the result with isValid() before using the parsed date: import { parse, isValid, format } from 'date-fns'; const parsed = parse(userInput, 'MM/dd/yyyy', new Date()); if (!isValid(parsed)) { throw new Error(`Invalid date string: ${userInput}`); } // Safe to use parsed date now return format(parsed, 'yyyy-MM-dd'); Do NOT pass the result directly to format() or date arithmetic functions without validation — they will throw RangeError on Invalid Date.
    costmediumin prodimmediate exceptionusers seeservice unavailablevisibilityvisible
    Sources[1][2]
  • parse · parse-incompatible-tokens
    error
    WhenFormat string contains incompatible token combinations. Common examples: - 'HH a' — 24-hour (HH) and AM/PM (a) together - 'YYYY MM' — week-year (YYYY) and month (MM) together without enabling useAdditionalWeekYearTokens - 'DD MM' — day of year (DD) and month (MM) together without useAdditionalDayOfYearTokens - Unescaped latin alphabet characters in format string (e.g., 'T' without being a valid token) These are programming errors caught at parse-time, not user input errors.
    ThrowsRangeError with message "The format string mustn't contain `X` and `Y` at the same time" or "Format string contains an unescaped latin alphabet character `X`".
    Required handlingFix the format string — these are developer errors, not user input errors. Use the date-fns format token reference: https://date-fns.org/docs/format Escape literal text with single quotes: parse('11/13', "MM'/'dd", new Date()) For YYYY/YY tokens, add options.useAdditionalWeekYearTokens: true For DD tokens, add options.useAdditionalDayOfYearTokens: true
    costlowin prodimmediate exceptionusers seeservice unavailablevisibilityvisible
    Sources[2][3]
  • format · format-invalid-date
    error
    WhenThe date argument is an Invalid Date (e.g., parse() returned an invalid result without isValid() check, or new Date('not-a-date'), or date arithmetic on null). format() checks isValid(originalDate) and throws immediately. This is the most common crash pattern with date-fns: const parsed = parse(userInput, 'MM/dd/yyyy', new Date()); // returns Invalid Date format(parsed, 'yyyy-MM-dd'); // THROWS RangeError — Invalid Date propagated here
    ThrowsRangeError with message "Invalid time value". This is a synchronous throw — not async. In Express/Next.js route handlers without proper error handling, this causes a 500 Internal Server Error.
    Required handlingAlways validate dates with isValid() before calling format(): import { parse, isValid, format } from 'date-fns'; function safeFormat(date: Date, formatStr: string): string { if (!isValid(date)) { throw new Error('Cannot format invalid date'); } return format(date, formatStr); } // Or with parse+format pipeline: const parsed = parse(userInput, 'MM/dd/yyyy', new Date()); if (!isValid(parsed)) { return res.status(400).json({ error: 'Invalid date input' }); } const formatted = format(parsed, 'yyyy-MM-dd');
    costmediumin prodimmediate exceptionusers seeservice unavailablevisibilityvisible
    Sources[4][5]
  • format · format-bad-token
    error
    WhenFormat string contains an unescaped latin alphabet character that is not a valid date-fns token (e.g., 'T' for timezone abbreviation when you meant literal 'T'), or uses protected tokens (YYYY for week-year, DD for day-of-year) without the corresponding options flag. Common mistake: using moment.js format strings with date-fns. Moment uses 'YYYY' for calendar year; date-fns uses 'yyyy'. Pasting moment format strings causes RangeError when the protected week-year token is used.
    ThrowsRangeError with message "Format string contains an unescaped latin alphabet character `X`" or a RangeError directing you to use yyyy instead of YYYY / d instead of D.
    Required handlingFix format strings to use date-fns tokens (not moment.js tokens): - yyyy (not YYYY) for calendar year - dd (not DD) for day of month - Wrap literal text in single quotes: format(date, "yyyy-MM-dd'T'HH:mm:ss") Reference: https://date-fns.org/docs/format#unicode-tokens
    costlowin prodimmediate exceptionusers seeservice unavailablevisibilityvisible
    Sources[4][3]
  • formatDistance · format-distance-invalid-date
    error
    WhenEither the date or baseDate argument is an Invalid Date (NaN). This is triggered by: - Passing parse() result without isValid() check - Date calculations that produce NaN (e.g., subDays(undefined, 5)) - Dates from API responses that were not validated (e.g., new Date(apiData.createdAt) where createdAt is null or malformed) The internal compareAsc() returns NaN when either date is invalid, and formatDistance() throws on NaN comparison result.
    ThrowsRangeError with message "Invalid time value".
    Required handlingValidate both dates before calling formatDistance(): import { formatDistance, isValid } from 'date-fns'; function safeFormatDistance(date: Date, baseDate: Date): string { if (!isValid(date) || !isValid(baseDate)) { return 'unknown time'; } return formatDistance(date, baseDate, { addSuffix: true }); } // Common usage in React components: const timeAgo = isValid(post.createdAt) ? formatDistance(post.createdAt, new Date(), { addSuffix: true }) : 'unknown';
    costmediumin prodimmediate exceptionusers seeservice unavailablevisibilityvisible
    Sources[6][7]
  • formatDistanceStrict · format-distance-strict-invalid-date
    error
    WhenEither the date or baseDate argument is Invalid Date. Same underlying cause as formatDistance-invalid-date: compareAsc() returns NaN, which triggers the throw.
    ThrowsRangeError with message "Invalid time value".
    Required handlingValidate both dates with isValid() before calling formatDistanceStrict(): import { formatDistanceStrict, isValid } from 'date-fns'; if (!isValid(startDate) || !isValid(endDate)) { throw new Error('Invalid date for distance calculation'); } return formatDistanceStrict(endDate, startDate);
    costmediumin prodimmediate exceptionusers seeservice unavailablevisibilityvisible
    Sources[8][9]
  • formatDistanceToNow · format-distance-to-now-invalid-date
    error
    WhenThe date argument is Invalid Date. Common in SaaS apps that pass API response timestamps directly to formatDistanceToNow() without validation: formatDistanceToNow(new Date(user.lastLoginAt)) // crashes if lastLoginAt is null/undefined formatDistanceToNow(parse(apiDate, 'MM/dd', new Date())) // crashes if parse returns Invalid Date
    ThrowsRangeError with message "Invalid time value".
    Required handlingValidate the date before calling formatDistanceToNow(): import { formatDistanceToNow, isValid } from 'date-fns'; // Safe wrapper const timeAgo = (date: Date | null): string => { if (!date || !isValid(date)) return 'never'; return formatDistanceToNow(date, { addSuffix: true }); }; // In React component: <span>{timeAgo(new Date(post.createdAt))}</span>
    costmediumin prodimmediate exceptionusers seeservice unavailablevisibilityvisible
    Sources[10][11]
  • formatDistanceToNowStrict · format-distance-to-now-strict-invalid-date
    error
    WhenThe date argument is Invalid Date. Identical trigger condition to formatDistanceToNow-invalid-date.
    ThrowsRangeError with message "Invalid time value".
    Required handlingSame as formatDistanceToNow — validate with isValid() before calling. import { formatDistanceToNowStrict, isValid } from 'date-fns'; if (!isValid(date)) return 'invalid'; return formatDistanceToNowStrict(date);
    costmediumin prodimmediate exceptionusers seeservice unavailablevisibilityvisible
    Sources[12][13]
  • formatISO · format-iso-invalid-date
    error
    WhenThe date argument is an Invalid Date (NaN timestamp). This is a critical path in API response serialization — if a date field is null, undefined, or malformed and passed to formatISO() before validation, the entire API response fails with "Invalid time value". Common in: - ORM records where date fields can be null (e.g., user.deletedAt) - API integrations where date parsing is not validated - Date calculations that produce NaN (arithmetic on null dates)
    ThrowsRangeError with message "Invalid time value".
    Required handlingValidate with isValid() before calling formatISO(): import { formatISO, isValid } from 'date-fns'; function serializeDate(date: Date | null | undefined): string | null { if (!date || !isValid(date)) return null; return formatISO(date); } // In API response building: const response = { id: record.id, createdAt: serializeDate(record.createdAt), // safe deletedAt: serializeDate(record.deletedAt), // safe even if null };
    costmediumin prodimmediate exceptionusers seeservice unavailablevisibilityvisible
    Sources[14][15]
  • isMatch · is-match-bad-format-token
    warning
    WhenThe format string contains invalid tokens (same conditions as parse-incompatible-tokens): - Unescaped latin alphabet characters - Protected tokens (YYYY, DD) without corresponding options flags - Incompatible token combinations Note: isMatch() returns false (not throws) when the input string doesn't match the format. It only THROWS when the format string itself is invalid.
    ThrowsRangeError with messages identical to parse() token errors: "Format string contains an unescaped latin alphabet character `X`" or "use yyyy instead of YYYY" / "use d instead of D".
    Required handlingFix the format string — these are developer errors. The common usage pattern (safe): import { isMatch, parse, isValid } from 'date-fns'; // Validate user input - isMatch returns boolean for input mismatch (doesn't throw) if (!isMatch(userInput, 'MM/dd/yyyy')) { return res.status(400).json({ error: 'Date must be MM/DD/YYYY format' }); } const date = parse(userInput, 'MM/dd/yyyy', new Date()); // date is now guaranteed valid since isMatch passed isMatch() is safe for user input validation — it only throws on developer format string errors.
    costlowin prodimmediate exceptionusers seeservice unavailablevisibilityvisible
    Sources[16][17]
  • formatISO9075 · format-iso9075-invalid-date
    error
    WhenThe date argument is an Invalid Date (NaN timestamp). This is the same trigger as format-iso-invalid-date — an unvalidated parse() result, null API response field, or date arithmetic on a null value passed to formatISO9075() without isValid() check. Common in MySQL/MariaDB ORM integrations where nullable date columns are serialized.
    ThrowsRangeError with message "Invalid time value".
    Required handlingValidate with isValid() before calling formatISO9075(): import { formatISO9075, isValid } from 'date-fns'; function toMysqlDatetime(date: Date | null | undefined): string | null { if (!date || !isValid(date)) return null; return formatISO9075(date); } // In ORM mapping: const record = { createdAt: toMysqlDatetime(entity.createdAt), // safe updatedAt: toMysqlDatetime(entity.updatedAt), // safe even if null };
    costmediumin prodimmediate exceptionusers seeservice unavailablevisibilityvisible
    Sources[18][19]
  • formatRelative · format-relative-invalid-date
    error
    WhenEither the date or baseDate argument is an Invalid Date (NaN timestamp). Both arguments must be valid before calling. Common crash pattern in scheduling UIs: formatRelative(parse(slot.startTime, 'HH:mm', new Date()), new Date()) — if parse() returns Invalid Date (malformed slot.startTime), formatRelative throws. Also triggered when either argument comes from an API response without null/isValid checks.
    ThrowsRangeError with message "Invalid time value".
    Required handlingValidate both dates with isValid() before calling formatRelative(): import { formatRelative, isValid } from 'date-fns'; function safeFormatRelative(date: Date, baseDate: Date): string { if (!isValid(date) || !isValid(baseDate)) { return 'unknown time'; } return formatRelative(date, baseDate); }
    costmediumin prodimmediate exceptionusers seeservice unavailablevisibilityvisible
    Sources[20][21]
  • formatRelative · format-relative-missing-locale-property
    error
    WhenA custom locale object is passed via options.locale that is missing one of the three required locale sub-objects: localize, formatLong, or formatRelative. This is a developer error when building custom locales or when importing locale objects from untrusted sources. Note: official date-fns locale packages (e.g., import { es } from 'date-fns/locale/es') always include all required properties and do NOT trigger this error.
    ThrowsRangeError with message "options.locale must contain `localize` property", "options.locale must contain `formatLong` property", or "options.locale must contain `formatRelative` property".
    Required handlingUse official date-fns locale packages or ensure custom locales implement all required properties. Official locales are safe: import { fr } from 'date-fns/locale/fr'; When building custom locales, verify all three required properties exist before use.
    costlowin prodimmediate exceptionusers seeservice unavailablevisibilityvisible
    Sources[20][22]
  • formatRFC3339 · format-rfc3339-invalid-date
    error
    WhenThe date argument is an Invalid Date (NaN timestamp). Critical in API serialization pipelines — any unvalidated date field from a database record or external API response that reaches formatRFC3339() will cause a 500 error. Common in REST APIs that serialize nullable timestamp columns without null/isValid checks.
    ThrowsRangeError with message "Invalid time value".
    Required handlingValidate with isValid() before calling formatRFC3339(): import { formatRFC3339, isValid } from 'date-fns'; // In API response builder: function serializeTimestamp(date: Date | null | undefined): string | null { if (!date || !isValid(date)) return null; return formatRFC3339(date); }
    costmediumin prodimmediate exceptionusers seeservice unavailablevisibilityvisible
    Sources[23][24]
  • formatRFC7231 · format-rfc7231-invalid-date
    warning
    WhenThe date argument is an Invalid Date (NaN timestamp). This surfaces in HTTP caching middleware that sets Last-Modified or Expires headers from database timestamps. If the database record has a null date field that's passed without validation, the header generation throws and typically causes a 500 response before headers are sent.
    ThrowsRangeError with message "Invalid time value".
    Required handlingValidate with isValid() before calling formatRFC7231(): import { formatRFC7231, isValid } from 'date-fns'; // In HTTP middleware: const lastModified = record.updatedAt && isValid(record.updatedAt) ? formatRFC7231(record.updatedAt) : undefined; if (lastModified) { res.setHeader('Last-Modified', lastModified); }
    costlowin prodimmediate exceptionusers seeservice unavailablevisibilityvisible
    Sources[25][26]
  • interval · interval-invalid-start-date
    error
    WhenThe start argument is an Invalid Date (NaN timestamp) or cannot be parsed to a valid date. This happens when building intervals from API response timestamps without validation: const range = interval(new Date(event.startTime), new Date(event.endTime)); If startTime is null or malformed, interval() throws TypeError immediately. Unlike most date-fns functions that throw RangeError, interval() throws TypeError.
    ThrowsTypeError with message "Start date is invalid".
    Required handlingValidate start date before calling interval(): import { interval, isValid } from 'date-fns'; function safeInterval(start: Date, end: Date) { if (!isValid(start)) throw new Error('Invalid start date'); if (!isValid(end)) throw new Error('Invalid end date'); return interval(start, end); }
    costmediumin prodimmediate exceptionusers seeservice unavailablevisibilityvisible
    Sources[27][28]
  • interval · interval-invalid-end-date
    error
    WhenThe end argument is an Invalid Date (NaN timestamp). Same pattern as interval-invalid-start-date but triggered by the end date. Both start and end must be valid. Note: interval() throws for the first invalid date it encounters — if both are invalid, only "Start date is invalid" is thrown (start is validated first).
    ThrowsTypeError with message "End date is invalid".
    Required handlingValidate both dates before calling interval(). See interval-invalid-start-date for the recommended safe wrapper pattern.
    costmediumin prodimmediate exceptionusers seeservice unavailablevisibilityvisible
    Sources[27][28]
  • interval · interval-end-before-start
    warning
    Whenoptions.assertPositive is true and end is before or equal to start. This is a validation feature — when assertPositive is passed, the caller asserts the interval must be forward-in-time. Useful for validating user-entered date ranges (start before end). However, if the error is not caught, it crashes any code that relies on the interval being valid (booking systems, scheduling apps, report generators).
    ThrowsTypeError with message "End date must be after start date".
    Required handlingWhen using assertPositive, wrap in try-catch or validate order before calling: import { interval, isValid, isBefore } from 'date-fns'; function createRange(start: Date, end: Date) { if (!isValid(start) || !isValid(end)) { throw new Error('Invalid date in range'); } if (!isBefore(start, end)) { return { error: 'End date must be after start date' }; } return interval(start, end, { assertPositive: true }); }
    costlowin prodimmediate exceptionusers seeservice unavailablevisibilityvisible
    Sources[27][28]
  • intlFormat · intl-format-invalid-date
    error
    WhenThe date argument is an Invalid Date (NaN timestamp). Intl.DateTimeFormat.format() propagates the error for invalid date values. The exact error type may vary by JS engine but in V8 (Node.js, Chrome) it throws RangeError. Used in locale-aware SaaS UIs that format dates from API responses — unvalidated null dates reach this function through rendering pipelines and crash the component/route.
    ThrowsRangeError (in V8/Node.js) when the date is Invalid Date. Error message varies by JS engine; do not rely on specific message text.
    Required handlingValidate with isValid() before calling intlFormat(): import { intlFormat, isValid } from 'date-fns'; function formatLocalized(date: Date, locale: string): string { if (!isValid(date)) return 'Invalid date'; return intlFormat(date, { year: 'numeric', month: 'long', day: 'numeric', }, { locale }); }
    costmediumin prodimmediate exceptionusers seeservice unavailablevisibilityvisible
    Sources[29][30]
  • intlFormatDistance · intl-format-distance-invalid-date
    error
    WhenEither the laterDate or earlierDate argument is an Invalid Date. The function computes differenceInSeconds() internally — when either date is Invalid, the difference is NaN, causing Intl.RelativeTimeFormat.format(NaN, unit) to throw. Common in SaaS notification systems or activity feeds that display "X ago" for events from external APIs — unvalidated timestamps from API responses crash the rendering path.
    ThrowsRangeError (in V8/Node.js) from Intl.RelativeTimeFormat.format() when the value is NaN (produced by invalid date arithmetic). Error message varies by JS engine.
    Required handlingValidate both dates with isValid() before calling intlFormatDistance(): import { intlFormatDistance, isValid } from 'date-fns'; function safeIntlFormatDistance(laterDate: Date, earlierDate: Date, locale?: string): string { if (!isValid(laterDate) || !isValid(earlierDate)) { return 'unknown'; } return intlFormatDistance(laterDate, earlierDate, { locale }); }
    costmediumin prodimmediate exceptionusers seeservice unavailablevisibilityvisible
    Sources[31][32]
  • lightFormat · light-format-invalid-date
    error
    WhenThe date argument is an Invalid Date (NaN timestamp). Same trigger as format-invalid-date: unvalidated parse() results, null API response dates, or date arithmetic on null values. lightFormat() is often used as a "drop-in" replacement for format() in performance-sensitive paths — developers familiar with format() may not realize lightFormat() has identical throw behavior on Invalid Date.
    ThrowsRangeError with message "Invalid time value".
    Required handlingValidate with isValid() before calling lightFormat(): import { lightFormat, isValid } from 'date-fns'; function formatDate(date: Date): string { if (!isValid(date)) throw new Error('Invalid date'); return lightFormat(date, 'yyyy-MM-dd HH:mm:ss'); }
    costmediumin prodimmediate exceptionusers seeservice unavailablevisibilityvisible
    Sources[33][34]
  • lightFormat · light-format-bad-token
    error
    WhenThe format string contains an unescaped latin alphabet character that is not a valid lightFormat token. lightFormat() supports only a limited token set (y, M, d, H, h, m, s, S, a) — attempting to use format() tokens like G (era), Q (quarter), w (week), or locale tokens (MMMM for full month name) throws RangeError. Developers switching from format() to lightFormat() for bundle size reduction may unknowingly use unsupported tokens.
    ThrowsRangeError with message "Format string contains an unescaped latin alphabet character `X`" where X is the invalid token character.
    Required handlingUse only lightFormat's supported tokens: y, M, d, H, h, m, s, S, a. For locale-aware or advanced tokens (era, quarter, week number, month names), use format() instead. Escape literal text in single quotes: lightFormat(date, "yyyy-MM-dd'T'HH:mm").
    costlowin prodimmediate exceptionusers seeservice unavailablevisibilityvisible
    Sources[33][34]

Sources

Every postcondition cites at least one of these. Numbered to match the footnotes above.

  1. [1]date-fns.org/docs/parsehttps://date-fns.org/docs/parse
  2. [2]github.com/date-fns/date-fnshttps://github.com/date-fns/date-fns/blob/main/src/parse/index.ts
  3. [3]github.com/date-fns/date-fnshttps://github.com/date-fns/date-fns/blob/main/docs/unicodeTokens.md
  4. [4]github.com/date-fns/date-fnshttps://github.com/date-fns/date-fns/blob/main/src/format/index.ts
  5. [5]date-fns.org/docs/formathttps://date-fns.org/docs/format
  6. [6]github.com/date-fns/date-fnshttps://github.com/date-fns/date-fns/blob/main/src/formatDistance/index.ts
  7. [7]date-fns.org/docs/formatDistancehttps://date-fns.org/docs/formatDistance
  8. [8]github.com/date-fns/date-fnshttps://github.com/date-fns/date-fns/blob/main/src/formatDistanceStrict/index.ts
  9. [9]date-fns.org/docs/formatDistanceStricthttps://date-fns.org/docs/formatDistanceStrict
  10. [10]github.com/date-fns/date-fnshttps://github.com/date-fns/date-fns/blob/main/src/formatDistanceToNow/index.ts
  11. [11]date-fns.org/docs/formatDistanceToNowhttps://date-fns.org/docs/formatDistanceToNow
  12. [12]github.com/date-fns/date-fnshttps://github.com/date-fns/date-fns/blob/main/src/formatDistanceToNowStrict/index.ts
  13. [13]date-fns.org/docs/formatDistanceToNowStricthttps://date-fns.org/docs/formatDistanceToNowStrict
  14. [14]github.com/date-fns/date-fnshttps://github.com/date-fns/date-fns/blob/main/src/formatISO/index.ts
  15. [15]date-fns.org/docs/formatISOhttps://date-fns.org/docs/formatISO
  16. [16]github.com/date-fns/date-fnshttps://github.com/date-fns/date-fns/blob/main/src/isMatch/index.ts
  17. [17]date-fns.org/docs/isMatchhttps://date-fns.org/docs/isMatch
  18. [18]github.com/date-fns/date-fnshttps://github.com/date-fns/date-fns/blob/main/src/formatISO9075/index.ts
  19. [19]date-fns.org/docs/formatISO9075https://date-fns.org/docs/formatISO9075
  20. [20]github.com/date-fns/date-fnshttps://github.com/date-fns/date-fns/blob/main/src/formatRelative/index.ts
  21. [21]date-fns.org/docs/formatRelativehttps://date-fns.org/docs/formatRelative
  22. [22]date-fns.org/docs/Localehttps://date-fns.org/docs/Locale
  23. [23]github.com/date-fns/date-fnshttps://github.com/date-fns/date-fns/blob/main/src/formatRFC3339/index.ts
  24. [24]date-fns.org/docs/formatRFC3339https://date-fns.org/docs/formatRFC3339
  25. [25]github.com/date-fns/date-fnshttps://github.com/date-fns/date-fns/blob/main/src/formatRFC7231/index.ts
  26. [26]date-fns.org/docs/formatRFC7231https://date-fns.org/docs/formatRFC7231
  27. [27]github.com/date-fns/date-fnshttps://github.com/date-fns/date-fns/blob/main/src/interval/index.ts
  28. [28]date-fns.org/docs/intervalhttps://date-fns.org/docs/interval
  29. [29]github.com/date-fns/date-fnshttps://github.com/date-fns/date-fns/blob/main/src/intlFormat/index.ts
  30. [30]date-fns.org/docs/intlFormathttps://date-fns.org/docs/intlFormat
  31. [31]github.com/date-fns/date-fnshttps://github.com/date-fns/date-fns/blob/main/src/intlFormatDistance/index.ts
  32. [32]date-fns.org/docs/intlFormatDistancehttps://date-fns.org/docs/intlFormatDistance
  33. [33]github.com/date-fns/date-fnshttps://github.com/date-fns/date-fns/blob/main/src/lightFormat/index.ts
  34. [34]date-fns.org/docs/lightFormathttps://date-fns.org/docs/lightFormat
Need a different package?
Request a profile