PHPExcel - read time value from a cell - php

I'm loading an Excel file that has cells with time data, e.g. 08:00:00. But when I try to read those cells with getValue(), it returns some floating point numbers instead of the actual time (in case of 08:00:00, it returns 0.3333333). Here's my code:
$objPHPExcel = PHPExcel_IOFactory::load($filename);
$objWorksheet = $objPHPExcel->getActiveSheet();
echo $objWorksheet->getCellByColumnAndRow(3, 5)->getValue();
How do I bypass this weird conversion?
PHPExcel 1.7.6 and Excel 2003 Worksheet (.xls)

You need to apply cell format for this:
$cell = $objWorksheet->getCellByColumnAndRow(3, 5);
$cell_value = PHPExcel_Style_NumberFormat::toFormattedString($cell->getCalculatedValue(), 'hh:mm:ss');
echo $cell_value;

Related

PHPSpreadsheet formula not working between dates

I want to calculate difference between 2 datetimes in hours with PHPSpreadsheet. This is how Excel does it:
A1 and A2 cells format is:
This is the result on web:
When I change value through PHPSpreadsheet, I get #VALUE! and different value formatting.
$reader = PhpSpreadsheet\IOFactory::createReader("Xlsx");
$target_file = __DIR__ . '/test.xlsx';
$spreadsheet = $reader->load($target_file);
$spreadsheet->getActiveSheet()->setCellValue('A1', '24.6.2020 12:30');
$writer = new PhpSpreadsheet\Writer\Html($spreadsheet);
$output = $writer->generateHTMLHeader();
$output .= $writer->generateStyles(true);
$output .= $writer->generateSheetData();
$output .= $writer->generateHTMLFooter();
$doc = new DOMDocument();
#$doc->loadHTML($output);
echo $doc->saveHTML();
I also tried with formatting like this 6/24/2020 14:30 but the result was same (#VALUE!)
$spreadsheet->getActiveSheet()->setCellValue('A1', '6/24/2020 14:30');
Anyone got any idea on how this should be done?
In an Excel document, dates are stored as numbers, not strings. So you need to pass the correct number to setCellValue().
PhpSpreadsheet provides the utility method Date::stringToExcel() to convert strings to Excel dates. You can use it like this:
$date = PhpSpreadsheet\Shared\Date::stringToExcel('2020-06-24 12:30');
$spreadsheet->getActiveSheet()->setCellValue('A1', $date);

PHPSpreadsheet and writing large numbers of decimal places

I'm having difficulty with PHPSpreadsheet when creating an XLSX file and attempting to write large numbers of decimal places to numerical values.
PHPSpreadsheet is rounding my 14 decimal place numbers, but I need them stored exactly as presented.
I'm using setFormatCode('0.00000000000000') as described in the documentation, but it's not working as I would expect.
Here's my test code:
<?php
require __DIR__ . '/vendor/autoload.php'; // Installed via composer
$spreadsheet = new \PhpOffice\PhpSpreadsheet\Spreadsheet();
$array = [
0.03790728347833,
1345.28748532874927,
121345.18248762894914, // all 14 DP
];
$format = '0.00000000000000'; // 14 DP
// write the data
$spreadsheet->getActiveSheet()
->fromArray($array, null, 'A1');
// Format the cells
$spreadsheet->getActiveSheet()->getStyle('A1:C1')->getNumberFormat()->setFormatCode($format);
// Column sizing
foreach(range('A','C') as $columnID)
{
$spreadsheet->getActiveSheet()->getColumnDimension($columnID)->setAutoSize(true);
}
$writer = new \PhpOffice\PhpSpreadsheet\Writer\Xlsx($spreadsheet);
$writer->save("test.xlsx");
// A1 = 0.03790728347833 - same
// A2 = 1345.28748532870000 - rounded
// A3 = 121345.18248763000000 - rounded
Could anyone provide a way to store this many decimal places without rounding?
This appears to be a limitation of Excel rather than PHPSpreadsheet.
Excel is limited to 15 significant figures according to Wikipedia.

PHPExcel toArray is changing date and time columns from XLSX format

I am using the excelToArray function found here: https://gist.github.com/calvinchoy/5821235
function excelToArray($filePath, $header = true) {
require_once("./PHPExcel/Classes/PHPExcel.php"));
//Create excel reader after determining the file type
$inputFileName = $filePath;
/** Identify the type of $inputFileName **/
$inputFileType = PHPExcel_IOFactory::identify($inputFileName);
/** Create a new Reader of the type that has been identified **/
$objReader = PHPExcel_IOFactory::createReader($inputFileType);
/** Set read type to read cell data onl **/
$objReader->setReadDataOnly(true);
/** Load $inputFileName to a PHPExcel Object **/
$objPHPExcel = $objReader->load($inputFileName);
//Get worksheet and built array with first row as header
$objWorksheet = $objPHPExcel->getActiveSheet();
//excel with first row header, use header as key
if($header){
$highestRow = $objWorksheet->getHighestRow();
$highestColumn = $objWorksheet->getHighestColumn();
$headingsArray = $objWorksheet->rangeToArray('A1:'.$highestColumn.'1',null, true, true, true);
$headingsArray = $headingsArray[1];
$r = -1;
$namedDataArray = array();
for ($row = 2; $row <= $highestRow; ++$row) {
$dataRow = $objWorksheet->rangeToArray('A'.$row.':'.$highestColumn.$row,null, true, true, true);
if ((isset($dataRow[$row]['A'])) && ($dataRow[$row]['A'] > '')) {
++$r;
foreach($headingsArray as $columnKey => $columnHeading) {
$namedDataArray[$r][$columnHeading] = $dataRow[$row][$columnKey];
}
}
}
}
else{
//excel sheet with no header
$namedDataArray = $objWorksheet->toArray(null,true,true,true);
}
return $namedDataArray;
}
I have two versions of a spreadsheet, one in CSV and one in Excel. Here they are:
CSV: https://drive.google.com/open?id=0B2GilRTNrTzKd3V3aEVET1NqSW8
XLSX: https://drive.google.com/open?id=0B2GilRTNrTzKdzJNZnh0cmhpa1E
When I upload the CSV using this function and var_dump the results I get
array (size=58)
0 =>
array (size=4)
'PD' => string '11/10/2016' (length=10)
'Pt' => string '9:12' (length=4)
'fd' => string '11/10/2017' (length=10)
'ft' => string '9:12' (length=4)
1 =>
array (size=4)...
But when I upload the XLSX I get:
array (size=58)
0 =>
array (size=5)
'PD' => float 42684
'Pt' => float 0.38333333333333
'fd' => float 43049
'ft' => float 0.38333333333333
'' => null
1 =>
array (size=5)
Notice that the PD goes from 11/10/2016 to 42684, and Pt from 9:12 to 0.38333...
What is causing the XLSX file to not be read in as it displays?
I have already read other stack questions, but I appear to be passing toArray the correct values. Not sure what I' missing...
MS Excel stores dates as a serialized timestamp, the number of days since 1t January 1900 (or 1st January 1904, depending on whether it is using the Windows or the Mac calendar). PHPExcel does likewise, so all dates/times are loaded to store in the spreadsheet object in exactly the way that MS Excel works with them.
So when you load a file with a human format date, it reads that as an MS Excel serialized timestamp. Ordinarily, it would also store the number format mask telling PHPExcel that this cell contains a timestamp value that shoud be formatted as a date, but you're telling PHPExcel's loader not to take this additional action by using $objReader->setReadDataOnly(true); which means store only the data, and not the formatting information.
Because PHPExcel desn't hve this additional formatting information, it cannot know that the cell contains something that should be dispayed as a date, so it can only dispay the serialized tiemstamp, which is really just a float.
In other words, don't do $objReader->setReadDataOnly(true); if you want dates to be treated as dates, or unless you want to do all the date handling yourself

PHPExcel, Save string without changes

I am using PHPExcel to save a multidimensional array data in a xls file
This is my code:
$arr = array(
array("01", "02", "03"),
array("04", "05", "06"),
);
// include PHPExcel library
$objPHPExcel = new PHPExcel();
$objPHPExcel->getActiveSheet()->fromArray($arr);
$objWriter = PHPExcel_IOFactory::createWriter($objPHPExcel, 'Excel5');
$objWriter->save("file.xls");
My problem is that starting nulls are removed in my xls file. For example is saved not as 01, but as 1.
How to solve this problem?
If you want a string with a numeric value to retain leading zeroes, then you have two choices:
Write it as a string using
$objPHPExcel->getActiveSheet()->getCell('A1')
->setValueExplicit(
'01',
PHPExcel_Cell_DataType::TYPE_STRING
);
(PHPExcel_Cell_DataType::TYPE_STRING is the default, so you don't actually have to specify that argument)
or allow it to be written as a number, and then set a format mask to display it with leading zeroes
$objPHPExcel->getActiveSheet()->getStyle('A1')
->getNumberFormat()
->setFormatCode("00");
EDIT
You can apply a style to a range of cells, not just to individual cells
$arr = array(
array("01", "02", "03"),
array("04", "05", "06"),
);
// include PHPExcel library
$objPHPExcel = new PHPExcel();
$objPHPExcel->getActiveSheet()->fromArray($arr);
$objPHPExcel->getActiveSheet()->getStyle('A1:C2')
->getNumberFormat()
->setFormatCode("00");
There seems to be a solution on the forum:
http://phpexcel.codeplex.com/discussions/31240
you need to set the row's attribute like this
$objPHPExcel->getActiveSheet()->getStyle('A0')->getNumberFormat()->setFormatCode("#");
but i don't know what format you need ,just look for the mannul

Unable to display date, time and numbers properly using PHPExcel

this is my first question in stackoverflow. I am trying to use PHPExcel to create an HTML table from .xlsx file. You can find my project in:
http://rahulr92.x10.mx/excel/index.php
Login with username 'admin' and you will find an option to 'View Table'. That page displays a table from previously uploaded .xlsx file. I am new to PHPExcel and used some standard code I found online. Here it is:
<?php
require_once '/Classes/PHPExcel.php';
$objReader = PHPExcel_IOFactory::createReader('Excel2007');
$objReader->setReadDataOnly(true);
$objPHPExcel = $objReader->load("..\excel.xlsx");
$objWorksheet = $objPHPExcel->getActiveSheet();
$highestRow = $objWorksheet->getHighestRow();
$highestColumn = $objWorksheet->getHighestColumn();
$highestColumnIndex = PHPExcel_Cell::columnIndexFromString($highestColumn);
$user=strtolower($_GET['user']);
$r_count=0;
echo '<table border="1">' . "\n";
for ($row = 5; $row <= $highestRow; ++$row) {
if ($row <7 || $user=="admin" || strstr(strtolower($objWorksheet->getCellByColumnAndRow(8, $row)->getValue()),$user ))
{
if($row>7)$r_count++;
for ($col = 0; $col <= $highestColumnIndex; ++$col) {
if(PHPExcel_Shared_Date::isDateTime($objWorksheet->getCellByColumnAndRow($col,$row)))
echo '<td>' . date("d M Y",PHPExcel_Shared_Date::ExcelToPHP($objWorksheet->getCellByColumnAndRow($col, $row))) . '</td>' ;
else
echo '<td>' . $objWorksheet->getCellByColumnAndRow($col, $row)->getValue() . '</td>' . "\n";
}
echo '</tr>' . "\n";
}
}
echo '</table>' . "\n";
echo "No. of Entries: ".$r_count;
?>
Sorry for the sub-optimal code. When I run the php file, I get a table and all strings in it are displayed properly but datetime and number fields are filled with seemingly random gibberish. Please have a look at it from the above link. I have done some research and found out about the isDateTime() function that way. But it isn't working or probably is used wrongly. I am having a tight deadline for this project, so it would be great if anyone could point me in the right direction. Really sorry if the answer was very obvious. Thanks a lot in advance.
Rahul
Don't set $objReader->setReadDataOnly(true); if you want to be able to identify date/time values... Excel stores dates/times as floating point numbers, and the only way to differentiate a number from a date/time is using the format masking: isDateTime() uses that format masking to identify if a value is a number or a date/time... $objReader->setReadDataOnly(true) tells the file reader to read only the data (the numbers) and to ignore format masks, so it only reads the raw data.
However, I'm not sure I understand exactly what you mean by "random gibberish"... numbers should still display as numbers... can you please give an example.
EDIT
Note that cell methods such as getFormattedValue() will return numbers as they are format masked in the workbook, so date/time values will be formatted as dates/times, numbers will be displayed with appropriate number of decimal places, thousand separators or currencies or percentages (if they had the appropriate formatting in the Excel file), so you don't need to test for isDateTime().... as long as $objReader->setReadDataOnly(true) wasn't set for teh reader.

Categories