PHPOffice/PhpSpreadsheet · error · PhpOffice\PhpSpreadsheet\Exception

Invalid timezone {$timezoneName}

Error message

Invalid timezone {$timezoneName}

What it means

Thrown by TimeZone::getTimeZoneAdjustment() when the timezone name supplied (or the globally configured one via TimeZone::setTimeZone()) fails validateTimeZone(). The method then builds a DateTimeZone, which requires a valid IANA zone identifier (e.g. 'Europe/Paris', 'UTC'); abbreviations like 'CST' or made-up strings are rejected.

Source

Thrown at src/PhpSpreadsheet/Shared/TimeZone.php:69

    {
        return self::$timezone;
    }

    /**
     *    Return the Timezone offset used for date/time conversions to/from UST
     * This requires both the timezone and the calculated date/time to allow for local DST.
     *
     * @param ?string $timezoneName The timezone for finding the adjustment to UST
     * @param float|int $timestamp PHP date/time value
     *
     * @return int Number of seconds for timezone adjustment
     */
    public static function getTimeZoneAdjustment(?string $timezoneName, $timestamp): int
    {
        $timezoneName = $timezoneName ?? self::$timezone;
        $dtobj = Date::dateTimeFromTimestamp("$timestamp");
        if (!self::validateTimeZone($timezoneName)) {
            throw new PhpSpreadsheetException("Invalid timezone $timezoneName");
        }
        $dtobj->setTimeZone(new DateTimeZone($timezoneName));

        return $dtobj->getOffset();
    }
}

View on GitHub (pinned to 65b080eef4)

Solutions

  1. Use full IANA identifiers everywhere ('America/New_York', 'Europe/Berlin', 'UTC') and normalize input before use.
  2. Check the setter's return: if (!TimeZone::setTimeZone($tz)) { /* reject */ } — never ignore it, since the failure converts into this later exception.
  3. Validate user-supplied names against DateTimeZone::listIdentifiers() (or TimeZone::validateTimeZone()) at the input boundary and keep a safe default.
  4. Catch PhpSpreadsheetException around date-heavy export code and map it to a configuration error message naming the bad timezone.

Example fix

// before
\PhpOffice\PhpSpreadsheet\Shared\TimeZone::setTimeZone('CST'); // returns false, ignored
$adjust = \PhpOffice\PhpSpreadsheet\Shared\TimeZone::getTimeZoneAdjustment(null, $ts);
// Invalid timezone CST

// after
$tz = in_array($userTz, DateTimeZone::listIdentifiers(), true) ? $userTz : 'UTC';
if (!\PhpOffice\PhpSpreadsheet\Shared\TimeZone::setTimeZone($tz)) {
    throw new RuntimeException("Unusable timezone: $tz");
}
Defensive patterns

Strategy: validation

Validate before calling

$valid = in_array($tzName, DateTimeZone::listIdentifiers(), true)
    || $tzName === 'UTC';
if (!$valid) { $tzName = 'UTC'; /* or reject */ }
$adjust = \PhpOffice\PhpSpreadsheet\Shared\TimeZone::getTimeZoneAdjustment($tzName, $ts);

Type guard

function validTimeZoneOrNull(?string $tz): ?string
{
    return ($tz !== null && (TimeZone::validateTimeZone($tz) || in_array($tz, DateTimeZone::listIdentifiers(), true)))
        ? $tz : null; // null → caller uses safe default
}

Try / catch

try { $adjust = TimeZone::getTimeZoneAdjustment($tzName, $ts); }
catch (\PhpOffice\PhpSpreadsheet\Exception $e) {
    if (str_contains($e->getMessage(), 'Invalid timezone')) {
        $adjust = TimeZone::getTimeZoneAdjustment('UTC', $ts); // safe fallback
    } else { throw $e; }
}

Prevention

When it happens

Trigger: Calling TimeZone::getTimeZoneAdjustment($tzName, $timestamp) directly, or after TimeZone::setTimeZone($bad) — note setTimeZone() itself only returns false on a bad name, so a silent failure there resurfaces as this exception at adjustment time. Typical bad inputs: 'CST', 'GMT+2', 'Eastern', trailing whitespace, or null falling back to a default that was never configured.

Common situations: Feeding user-profile timezone strings or $_POST/DB values straight into the API; config files with 'timezone: EST' instead of IANA names; setTimeZone() return value ignored so the bad value persists until a date conversion runs.

Related errors


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