mirror of
https://github.com/PHPOffice/PhpSpreadsheet.git
synced 2026-09-09 01:26:51 +00:00
ef81f19996
Fix #3899. Supersedes PR #4476, which will be changed to draft status and closed if this PR is merged. A standard cast from float to string in PHP can drop trailing decimal positions. This can lead to problems above and beyond the usual problems associated with floating point. See the superseded PR for a more complete explanation. `StringHelper::convertToString` is changed for how it handles floats. It will now do separate casts for the whole and decimal parts, and then combine the results. This affects `Cell::getValueString` and `Cell::getCalculatedValueString`. Xlsx Writer will now invoke `convertToString` before writing a float to Xml. Ods Writer already uses `getValueString`, so no change is needed there. Xls Writer writes its float values in binary, so no change is needed there. Tests are added for all 3 writers. Aside from fixing some problems, it might appear that this change introduces some new problems. For instance, setting a cell to `12345.6789` will now result in `12345.67890000000079` in the Xml. This difference is an illusion, merely a consequence of floating point rounding. If you run the following check under PhpUnit, it will pass: ```php self::assertSame(12345.6789, 12345.67890000000079); ```
51 lines
1.9 KiB
PHP
51 lines
1.9 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace PhpOffice\PhpSpreadsheetTests\Writer\Ods;
|
|
|
|
use DateTime;
|
|
use PhpOffice\PhpSpreadsheet\Shared\Date;
|
|
use PhpOffice\PhpSpreadsheet\Spreadsheet;
|
|
use PhpOffice\PhpSpreadsheetTests\Functional\AbstractFunctional;
|
|
|
|
class MicrosecondsTest extends AbstractFunctional
|
|
{
|
|
/**
|
|
* Test save and load XLSX file for round-trip DateTime.
|
|
* Ods Writer does not support date formats,
|
|
* and Reader does not support styles, so this
|
|
* test is slightly different than its Xls/Xlsx counterparts.
|
|
*/
|
|
public function testIssue4476(): void
|
|
{
|
|
$date = '2020-10-21';
|
|
$time = '14:55:31';
|
|
$originalDateTime = new DateTime("{$date}T{$time}");
|
|
$spreadsheet = new Spreadsheet();
|
|
$sheet = $spreadsheet->getActiveSheet();
|
|
$sheet->setCellValue('A1', Date::dateTimeToExcel($originalDateTime));
|
|
$reloadedSpreadsheet = $this->writeAndReload($spreadsheet, 'Ods');
|
|
$spreadsheet->disconnectWorksheets();
|
|
|
|
$rsheet = $reloadedSpreadsheet->getActiveSheet();
|
|
$rsheet->getStyle('A1')
|
|
->getNumberFormat()
|
|
->setFormatCode('yyyy-mm-dd hh:mm:ss.000');
|
|
/** @var float */
|
|
$reread = $rsheet->getCell('A1')->getValue();
|
|
$temp = Date::excelToDateTimeObject($reread)
|
|
->format('Y-m-d H:i:s.u');
|
|
self::assertSame("{$date} {$time}.000000", $temp, 'round trip works with float value');
|
|
$formatted = $rsheet->getCell('A1')->getFormattedValue();
|
|
self::assertSame("{$date} {$time}.000", $formatted, 'round trip works with formatted value');
|
|
/** @var float */
|
|
$temp = Date::stringToExcel($formatted);
|
|
$temp = Date::excelToDateTimeObject($temp)
|
|
->format('Y-m-d H:i:s.u');
|
|
self::assertSame("{$date} {$time}.000000", $temp, 'round trip works using stringToExcel on formatted value');
|
|
|
|
$reloadedSpreadsheet->disconnectWorksheets();
|
|
}
|
|
}
|