{"record":{"id":"74e545b3e14324cd","repo":"PHPOffice/PhpSpreadsheet","slug":"invalid-string-value-supplied-for-datatype-date","errorCode":null,"errorMessage":"Invalid string $value supplied for datatype Date","messagePattern":"Invalid string \\$value supplied for datatype Date","errorType":"exception","errorClass":"PhpOffice\\PhpSpreadsheet\\Exception","httpStatus":null,"severity":"error","filePath":"src/PhpSpreadsheet/Shared/Date.php","lineNumber":173,"sourceCode":"        throw new PhpSpreadsheetException('Invalid timezone');\n    }\n\n    /**\n     * @param mixed $value Converts a date/time in ISO-8601 standard format date string to an Excel\n     *                         serialized timestamp.\n     *                     See https://en.wikipedia.org/wiki/ISO_8601 for details of the ISO-8601 standard format.\n     */\n    public static function convertIsoDate(mixed $value, ?int $calendar = null): float|int\n    {\n        if (!is_string($value)) {\n            throw new Exception('Non-string value supplied for Iso Date conversion');\n        }\n\n        $date = new DateTime($value);\n        $dateErrors = DateTime::getLastErrors();\n\n        if (is_array($dateErrors) && ($dateErrors['warning_count'] > 0 || $dateErrors['error_count'] > 0)) {\n            throw new Exception(\"Invalid string $value supplied for datatype Date\");\n        }\n\n        $newValue = self::dateTimeToExcel($date, $calendar);\n\n        if (preg_match('/^\\s*\\d?\\d:\\d\\d(:\\d\\d([.]\\d+)?)?\\s*(am|pm)?\\s*$/i', $value) == 1) {\n            $newValue = fmod($newValue, 1.0);\n        }\n\n        return $newValue;\n    }\n\n    /**\n     * Convert a MS serialized datetime value from Excel to a PHP Date/Time object.\n     *\n     * @param float|int $excelTimestamp MS Excel serialized date/time value\n     * @param null|DateTimeZone|string $timeZone The timezone to assume for the Excel timestamp,\n     *                                           if you don't want to treat it as a UTC value\n     *                                           Use the default (UTC) unless you absolutely need a conversion","sourceCodeStart":155,"sourceCodeEnd":191,"githubUrl":"https://github.com/PHPOffice/PhpSpreadsheet/blob/65b080eef4d9fd11a5796135ab145883e5c3d6a6/src/PhpSpreadsheet/Shared/Date.php#L155-L191","documentation":"convertIsoDate() constructs a DateTime from the string, then rejects it if DateTime::getLastErrors() reports any warning or error (src/PhpSpreadsheet/Shared/Date.php:173). So the string parses syntactically but is semantically invalid — day out of range for the month, month 13, or other conditions PHP flags — and the same call paths as error 189 apply (setValueExplicit with TYPE_ISO_DATE, Ods reader).","triggerScenarios":"$cell->setValueExplicit('2023-02-30', DataType::TYPE_ISO_DATE); '2024-13-01'; user-typed dates where a d/m/Y value was normalized as Y-m-d producing impossible month/day pairs.","commonSituations":"User-supplied form data bound as ISO dates; scraped or OCR'd data with invalid days; locale-mismatched parsing (m/d/Y vs d/m/Y) yielding invalid combinations; February 29 in non-leap years.","solutions":["Validate before binding: DateTime::createFromFormat('Y-m-d', $v) plus getLastErrors(), or checkdate($m, $d, $y)","Normalize user input from its real source format (createFromFormat with the actual pattern) into Y-m-d","In import pipelines, catch the exception, log the cell coordinate, and quarantine the row instead of aborting the batch"],"exampleFix":"// before\n$cell->setValueExplicit('2023-02-30', DataType::TYPE_ISO_DATE); // throws\n\n// after\n$d = \\DateTime::createFromFormat('Y-m-d', '2023-02-30');\n$errs = \\DateTime::getLastErrors();\nif ($d === false || $errs['warning_count'] > 0 || $errs['error_count'] > 0) {\n    throw new \\InvalidArgumentException('Invalid date: 2023-02-30');\n}\n$cell->setValueExplicit('2023-02-30', DataType::TYPE_ISO_DATE);","handlingStrategy":"validation","validationCode":"function toStrictIsoDate(string $value): ?string\n{\n    $d = \\DateTime::createFromFormat('!Y-m-d', $value);\n    $errs = \\DateTime::getLastErrors();\n\n    if ($d === false || $errs['warning_count'] > 0 || $errs['error_count'] > 0) {\n        return null;\n    }\n\n    return $d->format('Y-m-d');\n}\n\nif (($iso = toStrictIsoDate($input)) === null) {\n    return 'invalid date';\n}\n$cell->setValueExplicit($iso, DataType::TYPE_ISO_DATE);","typeGuard":null,"tryCatchPattern":"try {\n    $cell->setValueExplicit($input, DataType::TYPE_ISO_DATE);\n} catch (\\PhpOffice\\PhpSpreadsheet\\Exception $e) {\n    if (str_contains($e->getMessage(), 'datatype Date')) {\n        rejectRow($rowNumber, $input);\n    }\n}","preventionTips":["checkdate() or createFromFormat+getLastErrors before binding","Parse user input with its real source format, then re-format to Y-m-d","Quarantine invalid rows instead of aborting whole imports"],"tags":["date","validation","value-binder","user-input"],"backgroundTag":"invalid-date-format","analyzedSha":"65b080eef4d9fd11a5796135ab145883e5c3d6a6","analyzedAt":"2026-08-17T05:40:41.646Z","schemaVersion":2},"datasetVersion":"2026-08-17T09:17:11.063Z"}