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

  1. Convert to an ISO string first: $cell->setValueExplicit($dt->format('Y-m-d\TH:i:s'), DataType::TYPE_ISO_DATE)
  2. For DateTime objects, store as a numeric Excel serial instead: setValueExplicit(Date::PHPToExcel($dt), DataType::TYPE_NUMERIC)
  3. 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

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


AI-assisted analysis of PHPOffice/PhpSpreadsheet@65b080eef4 (2026-08-17). Data as JSON: /api/errors/56fe317ccc24cf15. Report an issue: GitHub.