{"record":{"id":"21664c6d825fc84d","repo":"jackwener/OpenCLI","slug":"date-must-be-yyyy-mm-dd-got-value","errorCode":null,"errorMessage":"date must be YYYY-MM-DD, got \"${value}\"","messagePattern":"date must be YYYY-MM-DD, got \"(.+?)\"","errorType":"validation","errorClass":"ArgumentError","httpStatus":null,"severity":"error","filePath":"clis/12306/utils.js","lineNumber":94,"sourceCode":"    if (!trimmed) throw new ArgumentError('station must not be empty');\n    if (STATION_CODE_RE.test(trimmed)) {\n        const exact = stations.find((s) => s.code === trimmed);\n        if (exact) return exact;\n        throw new ArgumentError(`Unknown 12306 station telecode \"${trimmed}\"`);\n    }\n    const lower = trimmed.toLowerCase();\n    const exactName = stations.find((s) => s.name === trimmed);\n    if (exactName) return exactName;\n    const exactPinyin = stations.find((s) => s.pinyin === lower);\n    if (exactPinyin) return exactPinyin;\n    const exactAbbr = stations.find((s) => s.abbr === lower || s.short === lower);\n    if (exactAbbr) return exactAbbr;\n    throw new ArgumentError(`Unknown 12306 station \"${trimmed}\"`, 'Try the Chinese name (上海虹桥), the 3-4 letter telecode (AOH), or full pinyin (shanghaihongqiao).');\n}\n\nexport function validateDate(value) {\n    if (!DATE_RE.test(String(value ?? ''))) {\n        throw new ArgumentError(`date must be YYYY-MM-DD, got \"${value}\"`);\n    }\n    const [y, m, d] = value.split('-').map(Number);\n    const date = new Date(Date.UTC(y, m - 1, d));\n    if (date.getUTCFullYear() !== y || date.getUTCMonth() !== m - 1 || date.getUTCDate() !== d) {\n        throw new ArgumentError(`date \"${value}\" is not a real calendar date`);\n    }\n    return value;\n}\n\nexport function normalizeLimit(value, defaultValue, max) {\n    if (value === undefined || value === null || value === '') return defaultValue;\n    const n = Number(value);\n    if (!Number.isInteger(n) || n < 1) {\n        throw new ArgumentError(`limit must be a positive integer (1-${max})`);\n    }\n    if (n > max) {\n        throw new ArgumentError(`limit must be <= ${max}`);\n    }","sourceCodeStart":76,"sourceCodeEnd":112,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/12306/utils.js#L76-L112","documentation":"validateDate() requires the date string to match the YYYY-MM-DD format (DATE_RE) and rejects anything else. Thrown as ArgumentError before any network call is made, so callers get immediate feedback on malformed dates.","triggerScenarios":"Passing dates in other formats to date-taking commands: '2026/08/28', '28-08-2026', 'Aug 28 2026', ISO timestamps '2026-08-28T10:00:00Z', or empty/null values stringified as 'undefined'/'null'.","commonSituations":"Developers passing JavaScript Date objects (coerced to a different string format), reading locale-formatted dates from user input, or forgetting to format a Date before passing it.","solutions":["Format the value as YYYY-MM-DD before calling, e.g. date.toISOString().slice(0,10)","Accept user input in local format and convert it with a date-parsing step first","Validate the format in your own UI layer with the same YYYY-MM-DD regex"],"exampleFix":"// before\nawait query({ date: new Date() });\n// after\nconst d = new Date();\nawait query({ date: d.toISOString().slice(0, 10) }); // 'YYYY-MM-DD'","handlingStrategy":"validation","validationCode":"const DATE_RE = /^\\d{4}-\\d{2}-\\d{2}$/;\nfunction isValidDateString(v) {\n  const s = String(v ?? '');\n  if (!DATE_RE.test(s)) return false;\n  const [y, m, d] = s.split('-').map(Number);\n  const dt = new Date(Date.UTC(y, m - 1, d));\n  return dt.getUTCFullYear() === y && dt.getUTCMonth() === m - 1 && dt.getUTCDate() === d;\n}\nif (!isValidDateString(userDate)) throw new Error('date must be YYYY-MM-DD');","typeGuard":"function isDateString(v) {\n  return typeof v === 'string' && /^\\d{4}-\\d{2}-\\d{2}$/.test(v);\n}","tryCatchPattern":"try {\n  await query({ date });\n} catch (e) {\n  if (e instanceof ArgumentError && e.message.includes('YYYY-MM-DD')) {\n    console.error('Please supply the date as YYYY-MM-DD, e.g. 2026-08-28.');\n  } else throw e;\n}","preventionTips":["Always derive date strings with toISOString().slice(0,10)","Never pass Date objects or locale-formatted strings directly","Validate format at the UI/CLI boundary","Use a date library (e.g. date-fns format()) for formatting"],"tags":["input-validation","date-format","argument-error"],"backgroundTag":"invalid-date-format","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}