PHPOffice/PhpSpreadsheet · error · PhpOffice\PhpSpreadsheet\Exception
Non-string value supplied for Iso Date conversion
Error message
Non-string value supplied for Iso Date conversion
What it means
Date::convertIsoDate() converts ISO-8601 date strings to Excel serials and rejects any non-string input immediately (src/PhpSpreadsheet/Shared/Date.php:166). It is called from Cell::setValueExplicit() with DataType::TYPE_ISO_DATE (src/PhpSpreadsheet/Cell/Cell.php:344) and from the Ods reader when converting date-typed cell values, so ints, floats, DateTime objects, or null bound as ISO dates all fail.
Source
Thrown at src/PhpSpreadsheet/Shared/Date.php:166
if ($timeZone instanceof DateTimeZone || $timeZone === null) {
return $timeZone;
}
if (in_array($timeZone, DateTimeZone::listIdentifiers(DateTimeZone::ALL_WITH_BC))) {
return new DateTimeZone($timeZone);
}
throw new PhpSpreadsheetException('Invalid timezone');
}
/**
* @param mixed $value Converts a date/time in ISO-8601 standard format date string to an Excel
* serialized timestamp.
* See https://en.wikipedia.org/wiki/ISO_8601 for details of the ISO-8601 standard format.
*/
public static function convertIsoDate(mixed $value, ?int $calendar = null): float|int
{
if (!is_string($value)) {
throw new Exception('Non-string value supplied for Iso Date conversion');
}
$date = new DateTime($value);
$dateErrors = DateTime::getLastErrors();
if (is_array($dateErrors) && ($dateErrors['warning_count'] > 0 || $dateErrors['error_count'] > 0)) {
throw new Exception("Invalid string $value supplied for datatype Date");
}
$newValue = self::dateTimeToExcel($date, $calendar);
if (preg_match('/^\s*\d?\d:\d\d(:\d\d([.]\d+)?)?\s*(am|pm)?\s*$/i', $value) == 1) {
$newValue = fmod($newValue, 1.0);
}
return $newValue;
}
View on GitHub (pinned to 65b080eef4)
Solutions
- Convert to an ISO string first: $cell->setValueExplicit($dt->format('Y-m-d\TH:i:s'), DataType::TYPE_ISO_DATE)
- For DateTime objects, store as a numeric Excel serial instead: setValueExplicit(Date::PHPToExcel($dt), DataType::TYPE_NUMERIC)
- Guard with is_string($value) before binding as TYPE_ISO_DATE
Example fix
// before
$cell->setValueExplicit(20240101, DataType::TYPE_ISO_DATE); // throws
// after
$cell->setValueExplicit('2024-01-01', DataType::TYPE_ISO_DATE);
// or for DateTime objects:
$cell->setValueExplicit(
\PhpOffice\PhpSpreadsheet\Shared\Date::PHPToExcel($dateTime),
DataType::TYPE_NUMERIC
); Defensive patterns
Strategy: type-guard
Validate before calling
use PhpOffice\PhpSpreadsheet\Cell\DataType;
if (!is_string($value)) {
$value = match (true) {
$value instanceof \DateTime => $value->format('Y-m-d\TH:i:s'),
default => (string) $value,
};
}
$cell->setValueExplicit($value, DataType::TYPE_ISO_DATE); Type guard
function isIsoDateString(mixed $value): bool
{
return is_string($value) && preg_match('/^\d{4}-\d{2}-\d{2}/', $value) === 1;
} Prevention
- Only bind TYPE_ISO_DATE with strings you produced via format()
- Store DateTime objects as numeric serials (Date::PHPToExcel) with TYPE_NUMERIC
- Add is_string() guards in import mappers that feed TYPE_ISO_DATE
When it happens
Trigger: $cell->setValueExplicit(20240101, DataType::TYPE_ISO_DATE) — numeric literal instead of 'YYYY-MM-DD'; an import mapping that assigns DateTime objects or unix timestamps with TYPE_ISO_DATE; ODS files whose date cells contain unexpected node types.
Common situations: Binders/ETL code that maps DB column types to TYPE_ISO_DATE but passes native values; glue code ported from libraries that accepted mixed input; test fixtures using int dates.
Related errors
- Invalid string $value supplied for datatype Date
- #VALUE!
- #REF!
- #VALUE!
- Value could not be bound to cell.
AI-assisted analysis of PHPOffice/PhpSpreadsheet@65b080eef4 (2026-08-17).
Data as JSON: /api/errors/56fe317ccc24cf15.
Report an issue: GitHub.