jackwener/OpenCLI · error · ArgumentError

weibo user-posts ${name} must be a valid calendar date

Error message

weibo user-posts ${name} must be a valid calendar date

What it means

After the format check passes, readDate() parses the value as a Shanghai (+08:00) midnight timestamp and round-trips it through formatShanghaiDate. If the parse is non-finite or the round-trip differs from the input (e.g. 2024-02-30), the string was format-valid but not a real calendar date, so this ArgumentError is thrown.

Source

Thrown at clis/weibo/user-posts.js:36

}

function readLimit(raw) {
    const value = raw === undefined || raw === null || raw === '' ? DEFAULT_LIMIT : Number(raw);
    if (!Number.isInteger(value) || value < 1 || value > MAX_LIMIT) {
        throw new ArgumentError(`weibo user-posts limit must be an integer between 1 and ${MAX_LIMIT}`);
    }
    return value;
}

function readDate(raw, name) {
    if (raw === undefined || raw === null || raw === '') return null;
    const value = String(raw).trim();
    if (!DATE_RE.test(value)) {
        throw new ArgumentError(`weibo user-posts ${name} must use YYYY-MM-DD`);
    }
    const date = new Date(`${value}T00:00:00+08:00`);
    if (!Number.isFinite(date.getTime()) || value !== formatShanghaiDate(date)) {
        throw new ArgumentError(`weibo user-posts ${name} must be a valid calendar date`);
    }
    return value;
}

function formatShanghaiDate(date) {
    const parts = new Intl.DateTimeFormat('en-CA', {
        timeZone: 'Asia/Shanghai',
        year: 'numeric',
        month: '2-digit',
        day: '2-digit',
    }).formatToParts(date);
    const get = (type) => parts.find((part) => part.type === type)?.value;
    return `${get('year')}-${get('month')}-${get('day')}`;
}

function dateToTimestamp(date) {
    return Math.floor(new Date(`${date}T00:00:00+08:00`).getTime() / 1000);
}

View on GitHub (pinned to 49907e53dc)

Solutions

  1. Replace with a real calendar date, e.g. '2023-02-28' or '2024-02-29' for a leap year.
  2. Validate the date in your script with a Date round-trip before invoking the command.
  3. If generating ranges programmatically, use date arithmetic instead of string concatenation for the day component.

Example fix

// before
const start = `${year}-02-29`; // throws for non-leap 2023
// after
const start = isLeapYear(year) ? `${year}-02-29` : `${year}-02-28`;
Defensive patterns

Strategy: validation

Validate before calling

function isRealCalendarDate(s) {
  if (typeof s !== 'string' || !/^\d{4}-\d{2}-\d{2}$/.test(s)) return false;
  const d = new Date(`${s}T00:00:00Z`);
  return !Number.isNaN(d.getTime()) && d.toISOString().slice(0, 10) === s;
}
if (start && !isRealCalendarDate(start)) throw new Error(`not a real date: ${start}`);

Type guard

function isCalendarDate(v) {
  if (typeof v !== 'string') return false;
  const [y, m, d] = v.split('-').map(Number);
  const dt = new Date(Date.UTC(y, m - 1, d));
  return dt.getUTCFullYear() === y && dt.getUTCMonth() === m - 1 && dt.getUTCDate() === d;
}

Prevention

When it happens

Trigger: Calling start/end with syntactically valid but nonexistent dates such as '2023-02-29' (non-leap year), '2024-04-31', '2024-13-00', or any value where formatting the parsed date back does not reproduce the input.

Common situations: Hand-computed date arithmetic overflowing month ends, template strings like `${year}-02-30`, or dates typed manually with typos in day numbers.

Related errors


AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29). Data as JSON: /api/errors/e84ef0dce8dc9f52. Report an issue: GitHub.