{"record":{"id":"782ad96c52c6b05f","repo":"PHPOffice/PhpSpreadsheet","slug":"failed-to-modify-date-with-interval-modifier","errorCode":null,"errorMessage":"Failed to modify date with interval: $modifier","messagePattern":"Failed to modify date with interval: \\$modifier","errorType":"exception","errorClass":"PhpOffice\\PhpSpreadsheet\\Exception","httpStatus":null,"severity":"error","filePath":"src/PhpSpreadsheet/Shared/Date.php","lineNumber":639,"sourceCode":"             * @return bool Returns false if the error is not of type E_WARNING or if the message does not match\n             *              the specified condition. Throws PhpSpreadsheetException when conditions are met.\n             */\n            static function (int $severity, string $message): bool {\n                if ($severity !== E_WARNING) {\n                    return false;\n                }\n                if (!str_starts_with($message, 'DateTime::modify()')) {\n                    return false;\n                }\n\n                throw new PhpSpreadsheetException($message);\n            }\n        );\n\n        try {\n            $result = $dateTime->modify($modifier);\n            if ($result === false) {\n                throw new PhpSpreadsheetException('Failed to modify date with interval: ' . $modifier);\n            }\n\n            return $result;\n        } finally {\n            restore_error_handler();\n        }\n    }\n}\n","sourceCodeStart":621,"sourceCodeEnd":648,"githubUrl":"https://github.com/PHPOffice/PhpSpreadsheet/blob/65b080eef4d9fd11a5796135ab145883e5c3d6a6/src/PhpSpreadsheet/Shared/Date.php#L621-L648","documentation":"Date::safeModify() wraps DateTime::modify for Excel-serial conversion (excelToDateTimeObject builds modifiers like '+ N days' from the serial). On PHP < 8.3 a false return from modify() — unparseable or overflowing modifier — throws this message; on PHP >= 8.3 the same failure surfaces as DateMalformedStringException from DateTime itself instead. It therefore fires on out-of-range or absurd Excel timestamps.","triggerScenarios":"Calling Date::excelToDateTimeObject()/excelToTimestamp() with an astronomical serial (e.g. 3172011706730017, the value cited in the source comment); reading a cell whose numeric garbage carries a date number format so the value gets converted; extreme microsecond adjustments on the PHPToExcel path (Date.php:569).","commonSituations":"Columns mixing real dates with typed numbers (20250101) or formula blowups formatted as dates; corrupted cells; data-entry errors in date-formatted columns from third-party reports.","solutions":["Bound-check the serial before converting: valid Excel dates span roughly -693594 (1900) to 2958465 (9999)","Fix the source data or its number format so non-date numbers are not read as dates","Upgrade to PHP 8.3+ where the failure mode is the clearer DateMalformedStringException","Wrap read loops in try/catch on PhpSpreadsheet\\Exception and log the cell coordinate"],"exampleFix":"// before\n$dt = \\PhpOffice\\PhpSpreadsheet\\Shared\\Date::excelToDateTimeObject($cellValue); // huge serial throws\n\n// after\nif ($cellValue < -693594 || $cellValue > 2958465) {\n    throw new \\InvalidArgumentException(\"Not a valid Excel date serial: $cellValue\");\n}\n$dt = \\PhpOffice\\PhpSpreadsheet\\Shared\\Date::excelToDateTimeObject($cellValue);","handlingStrategy":"validation","validationCode":"const EXCEL_SERIAL_MIN = -693594; // 1900-01-01\nconst EXCEL_SERIAL_MAX = 2958465;  // 9999-12-31\n\nfunction isPlausibleExcelSerial(mixed $value): bool\n{\n    return is_int($value) || is_float($value)\n        ? $value >= EXCEL_SERIAL_MIN && $value <= EXCEL_SERIAL_MAX\n        : false;\n}","typeGuard":null,"tryCatchPattern":"try {\n    $dt = \\PhpOffice\\PhpSpreadsheet\\Shared\\Date::excelToDateTimeObject($serial);\n} catch (\\PhpOffice\\PhpSpreadsheet\\Exception | \\DateMalformedStringException $e) {\n    // PHP<8.3 throws the former, PHP>=8.3 the latter\n    $dt = null; // treat cell as non-date\n}","preventionTips":["Range-check serials before conversion, especially from date-formatted columns","Clean columns that mix real dates with typed numbers like 20250101","Test date conversions against your max data values on the target PHP version"],"tags":["date","overflow","datetime","php-version"],"backgroundTag":"date-arithmetic-overflow","analyzedSha":"65b080eef4d9fd11a5796135ab145883e5c3d6a6","analyzedAt":"2026-08-17T05:40:41.646Z","schemaVersion":2},"datasetVersion":"2026-08-17T09:17:11.063Z"}