PHPExcel toArray is changing date and time columns

2019-09-16 02:51发布

问题:

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...

回答1:

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