【问题标题】:PHPEXCEL get formatted date as is visible in excel file [duplicate]PHPEXCEL获取格式化日期,如在excel文件中可见[重复]
【发布时间】:2015-07-24 06:15:40
【问题描述】:

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

我搜索了整个网络和 stackoverflow,但没有一个解决方案能解决我的问题。 在 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;
}

【问题讨论】:

  • @miken32 不,这不是重复的,因为我在发布问题和答案之前检查了整个网络。请阅读此处提到的问题和答案,您会知道其中的区别。正如 Mark Ba​​ker(PhpExcel lib 协调员)自己试图帮助我。

标签: php phpexcel


【解决方案1】:

如果该字段确实包含 MS Excel 日期值,则对包含日期的字段的 getValue() 调用应返回类似 41959.00 的值......也就是说,基于数字的 MS Excel 序列化日期时间戳自 1900 年 1 月 1 日(或 1904 年 1 月 1 日,如果文件是使用 Mac 版本的 MS 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;
                }
            }
        }
    }
}

除了返回格式化的数据值之外,您还可以要求 PHPExcel 以 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;
}

【讨论】:

  • PHPExcel_Shared_Date::isDateTime($cell) 返回 false 所以上述建议在 getFormattedValue();该文件是使用 windows 和 MS-Excel 2013 创建的
  • 您没有使用setReadDataOnly(true) 加载文件吗?
  • 我做了$objPHPExcel = PHPExcel_IOFactory::load($filePath); $objPHPExcel-&gt;setReadDataOnly(true);
  • 我把上面的代码贴出来了,没有抛出异常请看提示@PHPExcel_Shared_Date::isDateTime($cell)
  • 注释掉$objPHPExcel-&gt;setReadDataOnly(true);....这一行因为这行告诉PHPExcel只加载原始数据,并忽略任何样式信息,如日期掩码,因此无法识别单元格是否为如果你使用这个,日期与否
【解决方案2】:

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

您在电子表格中用于这些日期的格式是可识别区域设置的日期格式,如果您查看单元格格式,则由 MS Excel 用星号 (*) 标记

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

以星号 (*) 开头的日期格式会响应为操作系统指定的区域日期和时间设置的更改。

因为 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"

所以(只要您从阅读器中删除了 setReadDataOnly(true) 调用,从阅读器调用,您仍然可以将日期单元格识别为日期,并手动格式化它们,覆盖默认的区域设置格式

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;
}

【讨论】:

  • 虽然电子表格中的日期是一种可识别区域设置的日期格式,如果我们查看单元格格式,MS Excel 会用星号 (*) 标记,但格式是 d-m-Y 的格式,这是可以理解的通过 PHP 这就是为什么将日期转换为 m-d-y 但由于它使用与 Excel 文件中的日期相同的分隔符,因此它会产生问题,因为 PHPEXCEL 提供的 m-d-y 被 php strtotime 函数理解为d-m-y 并且由于02-27-15 不是有效的d-m-y 格式(因为月份不能大于12),因此strtotime 函数return false 所以date 返回1970-01-01
  • 感谢#mark baker,我很重视您的建议,但它们并没有帮助。我找到了替代品并将列转换为m-d-Y,现在一切都很好,但它是替代品,而不是解决方案。因此,如果您有解决方案,请发布。或者,如果您知道 PHPEXCEL 库从哪里转换 d-m-Y 中的日期 || timestampm-d-y 然后请告诉我文件和行,我会相应地修改它以解决目的。因为这是PHPEXCEL lib 中的一个错误,我无法接受。
  • 这不是 PHPExcel 中的 错误,只是 PHPExcel 不知道您的语言环境,因此无法将日期转换为它不知道的格式.....如果您按照我上面显示的方式实现了我提供的代码,它应该可以正常工作....在将 MS 序列化时间戳值转换为格式化字符串时,您可以在其中准确指定希望应用的格式
  • 也与/- 无关。 MS Excel 序列化日期不包含这些字符,因为它是浮点数,unix 时间戳不包含这些字符,因为它是整数,PHP DateTime 对象也不包含......只有格式化的最终结果作为字符串包含其中任何一个字符
  • 我无法用任何非本地日期格式复制这个“错误”.....我什至完全重写了日期格式代码(尽管出于其他原因)并将其推送到昨晚github上的1.8分支.....但是我无法复制任何问题,很难知道它是否已修复
【解决方案3】:

我找到了解决办法:

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

如果日期类似于16/11/2014,当传递给strtotime 时将导致false,因为日期应该是m/d/Y 格式strtotime。因此,如果您将格式更改为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;
}

【讨论】:

  • 感谢#mark baker 通过您的最后一次提交让我知道文件和功能。这对我帮助很大。
猜你喜欢
  • 2018-04-24
  • 2014-04-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-03-10
相关资源
最近更新 更多