Credit Card Expiry Validation With Clock Injection

Parse MM/YY card expiry values, compare them against an injectable clock and report whether the card is valid through month end.

JavascriptForm Validation

Code

snippet
export function parseExpiry(value) {
  if (typeof value !== "string") throw new TypeError("expiry must be a string");
  const match = /^(0[1-9]|1[0-2])\s*\/\s*(\d{2})$/.exec(value.trim());
  if (!match) throw new RangeError("expiry must use MM/YY format");
  const month = Number(match[1]);
  const year = 2000 + Number(match[2]);
  return { month, year };
}

export function isExpired(value, now = new Date()) {
  const { month, year } = parseExpiry(value);
  if (Number.isNaN(now.getTime())) throw new TypeError("now must be a valid Date");
  const endOfMonth = new Date(Date.UTC(year, month, 1));
  return now.getTime() >= endOfMonth.getTime();
}

export function validateExpiry(value, now = new Date()) {
  const parsed = parseExpiry(value);
  const expired = isExpired(value, now);
  return {
    valid: !expired,
    reason: expired ? "expired" : null,
    month: parsed.month,
    year: parsed.year,
  };
}