Our software is designed to track work hours, so we need to generate Excel files that include negative time values.
According to the PhpSpreadsheet documentation:
Note that the baseline date itself is day 1; so strictly speaking, the base date 0 is ‘1899-12-31’: Excel considers any value between 0 and 1 as purely a time value. Attempting to display 0 using a date format mask like ‘yyyy-mm-dd’ will result in an invalid date like ‘1900-01-00’ rather than ‘1899-12-31.’ However, when using a time format mask like ‘hh:mm:ss,’ it will appear as ’00:00:00′ (midnight). Values less than 0 are invalid as dates or times, so a negative value in a cell with a date ‘Number Format Mask’ will display as ‘############’ in Excel.
Open/LibreOffice and Gnumeric don’t have this limitation, and negative date/timestamp values are recognized and formatted correctly. However, it is recommended not to rely on this behavior when working with PhpSpreadsheet."
In version 1.19, we resolved this issue by configuring the following setting:
use PhpOfficePhpSpreadsheetSharedDate as Shared_Date;
Shared_Date::setExcelCalendar(Shared_Date::CALENDAR_MAC_1904);
Recently we upgraded to version 2.2 and this configuration no longer works.
Is there any alternative solution?
2
Answers
As suggested here: https://github.com/PHPOffice/PhpSpreadsheet/discussions/4265#discussioncomment-11488292
The solution is:
In PhpSpreadsheet version 2.2, the way negative time values are handled has changed, and the previous method with
Shared_Date::setExcelCalendar
is no longer effective.To work with negative time values correctly in Excel using PhpSpreadsheet, you need to use custom number formatting. Excel does not support negative date or time values by default, but you can format them to display correctly with a custom format.
CALENDAR_MAC_1904
option), you can do this:PhpOfficePhpSpreadsheetSharedDate::setExcelCalendar(PhpOfficePhpSpreadsheetSharedDate::CALENDAR_MAC_1904);
Example for handling negative time:
$spreadsheet = new PhpOfficePhpSpreadsheetSpreadsheet(); $sheet = $spreadsheet->getActiveSheet();
// Set negative time value
$negativeTime = -0.5;
// Set cell value and apply the custom time format
$sheet->setCellValue('A1', $negativeTime);
// Time format that handles negative values
$sheet->getStyle('A1')->getNumberFormat()->setFormatCode('[hh]:mm:ss');
// Save file or output as needed
This will allow Excel to show the negative time value correctly instead of ############.