{"record":{"id":"27caf74abca6361b","repo":"can1357/oh-my-pi","slug":"invalid-date-27caf7","errorCode":null,"errorMessage":"Invalid Date","messagePattern":"Invalid Date","errorType":"exception","errorClass":"RangeError","httpStatus":null,"severity":"warning","filePath":"packages/mnemopi/src/util/datetime.ts","lineNumber":22,"sourceCode":"const TZ_RE = /(?:Z|[+-]\\d\\d:?\\d\\d)$/;\nconst DATE_ONLY_RE = /^\\d{4}-\\d{2}-\\d{2}$/;\nconst TS_CACHE = new LruCache<string, Date>(2000);\n\nexport type QueryTime = string | Date | null | undefined;\n\nexport function parseIsoDateTimeUtc(value: string): Date {\n\tlet text = value.trim();\n\tif (!text) throw new RangeError(\"Invalid ISO datetime: empty string\");\n\tif (DATE_ONLY_RE.test(text)) text += \"T00:00:00Z\";\n\telse if (!TZ_RE.test(text)) text += \"Z\";\n\tconst date = new Date(text);\n\tif (Number.isNaN(date.getTime())) throw new RangeError(`Invalid ISO datetime: ${value}`);\n\treturn date;\n}\n\nexport function normalizeDateTimeUtc(value: Date): Date {\n\tconst time = value.getTime();\n\tif (Number.isNaN(time)) throw new RangeError(\"Invalid Date\");\n\treturn new Date(time);\n}\n\nexport function parseQueryTime(value: QueryTime): Date {\n\tif (value === null || value === undefined) return new Date();\n\treturn typeof value === \"string\" ? parseIsoDateTimeUtc(value) : normalizeDateTimeUtc(value);\n}\n\nexport function parseTsFast(value: string): Date | undefined {\n\tif (!value) return undefined;\n\tconst cached = TS_CACHE.get(value);\n\tif (cached !== undefined) return cached;\n\ttry {\n\t\tconst parsed = parseIsoDateTimeUtc(value);\n\t\tTS_CACHE.set(value, parsed);\n\t\treturn parsed;\n\t} catch {\n\t\treturn undefined;","sourceCodeStart":4,"sourceCodeEnd":40,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/mnemopi/src/util/datetime.ts#L4-L40","documentation":"normalizeDateTimeUtc() validates an existing Date and returns a UTC-normalized copy. If the input Date holds NaN (an invalid date), it throws a RangeError('Invalid Date'). This catches Dates constructed from bad input (new Date('garbage')) before they propagate into query filters or stored timestamps.","triggerScenarios":"Calling normalizeDateTimeUtc(new Date('invalid')), normalizeDateTimeUtc(new Date(NaN)), or parseQueryTime(dateObj) with such a Date; also passing a Date that another parser failed to construct.","commonSituations":"new Date(undefined) from missing config values, arithmetic on dates producing NaN (subtracting invalid dates), JSON deserialization yielding strings that were new Date()'d unvalidated, or new Date(numberString) mis-parsing numeric strings.","solutions":["Check isNaN(d.getTime()) at the input boundary before calling.","Ensure values are parsed via parseIsoDateTimeUtc() for strings, which gives a precise error message.","Guard optional values: only construct a Date when the source value is present and valid.","If NaN came from date arithmetic, log the operands — one of them was already invalid."],"exampleFix":"// before\nconst t = parseQueryTime(new Date(config.since)); // config.since undefined -> Invalid Date\n// after\nconst since = config.since ? parseIsoDateTimeUtc(String(config.since)) : null;\nconst t = parseQueryTime(since); // null -> now","handlingStrategy":"type-guard","validationCode":"function isValidDate(d) {\n  return d instanceof Date && !Number.isNaN(d.getTime());\n}\nif (!isValidDate(candidate)) throw new Error(`Bad date from source: ${String(sourceValue)}`);\nconst t = parseQueryTime(candidate);","typeGuard":"function isValidDate(d) { return d instanceof Date && !Number.isNaN(d.getTime()); }\n// use: if (isValidDate(d)) parseQueryTime(d);","tryCatchPattern":"try {\n  const t = normalizeDateTimeUtc(d);\n} catch (err) {\n  if (err instanceof RangeError && err.message === 'Invalid Date') {\n    logger.warn('Invalid Date reached normalizeDateTimeUtc', { raw: String(sourceValue) });\n    return new Date(); // or rethrow with source context\n  }\n  throw err;\n}","preventionTips":["Never call new Date() on unvalidated strings — use parseIsoDateTimeUtc instead","Check isNaN(d.getTime()) right after any new Date(...) construction","Log the original raw value alongside the Date so NaN sources are traceable","Avoid Date arithmetic on possibly-invalid dates; validate operands first"],"tags":["datetime","invalid-date","validation","range-error"],"backgroundTag":"invalid-date","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}