PHPEXCEL 获取 excel 文件中可见的格式化日期

PHPEXCEL get formatted date as is visible in excel file

我正在尝试使用 PhpExcel 库导入 excel 文件 对于所有其他字段,getValue() 函数有效,但当它遇到格式为 ms-excel2013 中设置的日期的字段时 exel 文件中的日期字段格式为 d-m-Y,如 16-11-2014 但是当我尝试导入它时,它的值 getValue() returns 11-16-14 当进一步传递给 strtotimereturns false 又导致 date('Y-m-d',strtotime($date)) 到return 1970-01-01.

我搜索了整个网络和 Whosebug,但 none 解决方案解决了我的问题。 在 excel 文件中,我看到日期为 16-11-2014 并希望它按原样导入。

这是代码

protected function importExcel($filePath) {
    $excelData = array();
    if ($filePath) {
        $objPHPExcel = PHPExcel_IOFactory::load($filePath);
        $objPHPExcel->setReadDataOnly(true);
        foreach ($objPHPExcel->getWorksheetIterator() as $worksheet) {
            $worksheetTitle = $worksheet->getTitle();
            $highestRow = $worksheet->getHighestRow(); // e.g. 10
            $highestColumn = $worksheet->getHighestColumn(); // e.g 'F'
            $highestColumnIndex = PHPExcel_Cell::columnIndexFromString($highestColumn);
            $nrColumns = ord($highestColumn) - 64;
            $data = array();
            for ($row = 1; $row <= $highestRow; ++$row) {
                $values = array();
                for ($col = 0; $col < $highestColumnIndex; ++$col) {
                    $cell = $worksheet->getCellByColumnAndRow($col, $row);
                    if (PHPExcel_Shared_Date::isDateTime($cell))
                        throw new Exception("is date time"); // just a check
                    $val = $cell->getValue();
                    if (isset($val) && $val)
                        $data[$row][$col] = $val;
                }
            }
            $excelData[$worksheetTitle] = $data;
        }
        return $excelData;
    }
    return FALSE;
}

对包含日期的字段的 getValue() 调用应该 return 类似 41959.00 的值,如果该字段确实包含 MS Excel 日期值... . 也就是说,一个 MS Excel 序列化日期时间戳基于自 1900 年 1 月 1 日以来的天数(如果文件是使用 MS Mac 版本创建的,则为 1904 年 1 月 1 日)Excel)

要获取格式化的日期字符串,您需要调用 getFormattedValue();然后 PHPExcel 使用该单元格的数字格式掩码根据该掩码格式化日期。

要确定单元格是否包含 MS 序列化日期时间戳,您可以先调用 PHPExcel_Shared_Date::isDateTime()

foreach ($objPHPExcel->getWorksheetIterator() as $worksheet) {
    echo 'Worksheet - ' , $worksheet->getTitle() , EOL;

    foreach ($worksheet->getRowIterator() as $row) {
        echo '    Row number - ' , $row->getRowIndex() , EOL;

        $cellIterator = $row->getCellIterator();
        $cellIterator->setIterateOnlyExistingCells(false); // Loop all cells, even if it is not set
        foreach ($cellIterator as $cell) {
            if (!is_null($cell)) {
                echo '        Cell - ' , $cell->getCoordinate() , ' - ';
                if (PHPExcel_Shared_Date::isDateTime($cell)) {
                    echo $cell->getFormattedValue() , EOL;
                } else {
                    echo $cell->getValue() , EOL;
                }
            }
        }
    }
}

除了 return 格式化数据值,您还可以要求 PHPExcel 将日期 return 作为 Unix 时间戳,或作为 PHP DateTime 对象代替;然后您就可以使用 PHP 的内置日期函数或 DateTime 方法对其进行格式化。

if (PHPExcel_Shared_Date::isDateTime($cell)) {
    $unixTimeStamp = PHPExcel_Shared_Date::ExcelToPHP($cell->getValue());
    echo date('d-M-Y H:i:s', $unixTimeStamp), PHP_EOL;
}

if (PHPExcel_Shared_Date::isDateTime($cell)) {
    $dateTimeObject = PHPExcel_Shared_Date::ExcelToPHPObject($cell->getValue());
    echo $dateTimeObject->format('d-M-Y H:i:s'), PHP_EOL;
}

我已经检查了你提供的文件,查看你的日期问题。

您在电子表格中用于这些日期的格式是区域设置感知日期格式,如果您查看单元格格式[=15],MS Excel 会用星号 (*) 标记=]

这意味着(引用Excel关于格式掩码显示的注释):

Date formats that begin with an asterisk (*) respond to changes in regional date and time settings that are specified for the Operating System.

由于 PHPExcel 不识别区域设置,但确实将格式掩码识别为日期值,因此它使用通用格式。


运行以下代码

var_dump($objPHPExcel->getActiveSheet()->getCell('I5')->getValue());
var_dump(PHPExcel_Shared_Date::isDateTime($objPHPExcel->getActiveSheet()->getCell('I5')));
var_dump($objPHPExcel->getActiveSheet()->getCell('I5')->getStyle()->getNumberFormat()->getFormatCode());
var_dump($objPHPExcel->getActiveSheet()->getCell('I5')->getFormattedValue());

给予

float(42062)
bool(true)
string(8) "mm-dd-yy"
string(8) "02-27-15"

因此(只要您从 Reader 中删除了 setReadDataOnly(true) 调用,从 Reader 中调用,您仍然可以将日期单元格识别为日期,并对其进行格式化手动覆盖默认的区域设置格式

if (PHPExcel_Shared_Date::isDateTime($objPHPExcel->getActiveSheet()->getCell('I5'))) {
    $dateTimeObject = PHPExcel_Shared_Date::ExcelToPHPObject($objPHPExcel->getActiveSheet()->getCell('I5')->getValue());
    echo $dateTimeObject->format('d-m-Y'), PHP_EOL;
}

我找到了解决方案:

方法_formatAsDate 文件PHPExcel/Style/NumberFormat.php

如果日期类似于 16/11/2014,当传递给 strtotime 时将导致 false,因为日期应该采用 m/d/Y 格式 [=12] =].因此,如果您将格式更改为 m/d/Y 如果它是 d/m/Y 那么解决方案将始终是正确的。

早些时候:

  1. 16/11/2014==1970-01-01(行:1)
  2. 16/11/2014==1970-01-01(行:2)
  3. 23/12/2014==1970-01-01(行:3)。

现在:

  1. 11/16/2014==2014-11-16(行:1)
  2. 11/16/2014==2014-11-16(行:2)
  3. 12/23/2014==2014-12-23(行:3)

导入文件的代码仍然相同且简单:

protected function importExcel($filePath) {
    $excelData = array();
    if ($filePath) {
        $objPHPExcel = PHPExcel_IOFactory::load($filePath);
        foreach ($objPHPExcel->getWorksheetIterator() as $worksheet) {
            $worksheetTitle = $worksheet->getTitle();
            $highestRow = $worksheet->getHighestRow(); // e.g. 10
            $highestColumn = $worksheet->getHighestColumn(); // e.g 'F'
            $highestColumnIndex = PHPExcel_Cell::columnIndexFromString($highestColumn);
            $nrColumns = ord($highestColumn) - 64;
            $data = array();
            for ($row = 1; $row <= $highestRow; ++$row) {
                $values = array();
                for ($col = 0; $col < $highestColumnIndex; ++$col) {
                    $cell = $worksheet->getCellByColumnAndRow($col, $row);
                    $val = $cell->getValue();
                    if (isset($val) && $val)
                        $data[$row][$col] = $val;
                }
            }
            $excelData[$worksheetTitle] = $data;
        }
        return $excelData;
    }
    return FALSE;
}