You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用Spreadsheet_Excel_Reader解析xls日期时多一天的问题咨询

问题描述

我有一个包含日程的.xls文件,其中一列日期格式为02.10.2018(d.m.Y)。使用Spreadsheet_Excel_Reader解析该文件时,该列日期返回值比实际多1天:原日期为02.10.2018,解析后输出为03.10.2018。但如果在日期值间使用逗号、反斜杠等分隔符,解析得到的日期则为正确值。

附代码:

function exceltohtml($file = NULL) { 
    $data = new Spreadsheet_Excel_Reader(); 
    $data->setOutputEncoding('utf-8'); 
    $data->setUTFEncoder('mb'); 
    if (!file_exists($_SERVER['DOCUMENT_ROOT'] . $file)) { 
        echo 'Необходимо залить файл настроек'; 
        die(); 
    } 
    // 2. Проверка эксель пустой/не пустой 
    $data->read($_SERVER['DOCUMENT_ROOT'] . $file); 
    if (empty($data->sheets[0]['cells']) || !count($data->sheets[0]['cells'])) { 
        echo 'Эксель файл некорректный или пустой'; 
        die(); 
    } else { 
        $rows = $data->sheets[0]['cells']; 
        return $rows; 
    } 
}

截图:
Excel日期解析错误截图


问题原因与解决方案

为什么会出现这个问题?

这个坑其实是老旧的Spreadsheet_Excel_Reader库+Excel历史bug共同导致的:

  • 当日期用.分隔时,Excel会自动把这列识别为日期数值格式——Excel内部把日期存储为从1900年1月0日开始计数的浮点数,但它有个历史bug:错误地将1900年标记为闰年,导致1900年3月1日之后的日期数值比实际多1天。
  • 而Spreadsheet_Excel_Reader这个库年代久远,没有正确处理这个Excel的闰年bug,在把Excel的日期数值转换为PHP日期时,直接用了原始偏移值,就导致日期多算了1天。
  • 当你用逗号、反斜杠等分隔符时,Excel会把日期当成纯文本存储,库直接读取字符串,自然不会触发这个数值转换的错误。

无需特殊技巧的解决方法

方法1:修复Spreadsheet_Excel_Reader的日期转换逻辑(最快)

找到库的核心文件(一般是reader.php),定位到ExcelToPHP函数——这个函数负责把Excel日期数值转成PHP时间戳。原函数大概是这样:

function ExcelToPHP($dateValue = 0) {
    if ($dateValue > 0) {
        $utcDays = $dateValue - 25569;
        $returnValue = round($utcDays * 86400);
        if (($returnValue <= PHP_INT_MAX) && ($returnValue >= -PHP_INT_MAX)) {
            $returnValue = (integer) $returnValue;
        }
        return $returnValue;
    } else {
        return false;
    }
}

我们需要给它加上Excel闰年bug的修正:如果日期数值大于60(对应1900年3月1日),偏移值从25569改成25568。修改后的函数:

function ExcelToPHP($dateValue = 0) {
    if ($dateValue > 0) {
        // 修正Excel 1900年闰年bug
        $offset = $dateValue > 60 ? 25568 : 25569;
        $utcDays = $dateValue - $offset;
        $returnValue = round($utcDays * 86400);
        if (($returnValue <= PHP_INT_MAX) && ($returnValue >= -PHP_INT_MAX)) {
            $returnValue = (integer) $returnValue;
        }
        return $returnValue;
    } else {
        return false;
    }
}

保存后重新解析文件,日期就会正确显示了。

方法2:换成现代的PhpSpreadsheet库(推荐)

Spreadsheet_Excel_Reader已经多年没有维护,不仅日期处理有bug,还不支持新版Excel格式。推荐换成PhpSpreadsheet(原PHPExcel的官方继任者),它对日期的处理非常精准,而且功能更全面。

用PhpSpreadsheet重写你的函数:

function exceltohtml($file = NULL) { 
    // 确保已通过Composer安装PhpSpreadsheet,引入自动加载文件
    require 'vendor/autoload.php';

    $filePath = $_SERVER['DOCUMENT_ROOT'] . $file;
    if (!file_exists($filePath)) { 
        echo 'Необходимо залить файл настроек'; 
        die(); 
    } 

    // 加载XLS文件
    $reader = new \PhpOffice\PhpSpreadsheet\Reader\Xls();
    $spreadsheet = $reader->load($filePath);
    $worksheet = $spreadsheet->getActiveSheet();
    
    $rows = [];
    // 遍历所有行
    foreach ($worksheet->getRowIterator() as $row) {
        $cellIterator = $row->getCellIterator();
        $cellIterator->setIterateOnlyExistingCells(false); // 遍历所有单元格(包括空的)
        $rowData = [];
        foreach ($cellIterator as $cell) {
            // 自动识别日期格式并输出正确的格式化值
            if ($cell->getDataType() === \PhpOffice\PhpSpreadsheet\Cell\Cell::TYPE_DATE) {
                $rowData[] = $cell->getFormattedValue();
            } else {
                $rowData[] = $cell->getValue();
            }
        }
        $rows[] = $rowData;
    }

    if (empty($rows)) {
        echo 'Эксель файл некорректный или пустой'; 
        die(); 
    }

    return $rows;
}

这个方法不需要修改旧库代码,一劳永逸解决日期问题,还能兼容更多Excel特性。

方法3:临时手动修正日期(应急方案)

如果暂时没法改库或换库,可以在解析后手动给日期减1天:

// 假设$rows是你从原函数获取的解析结果
foreach ($rows as &$row) {
    foreach ($row as &$cell) {
        // 匹配d.m.Y格式的日期
        if (preg_match('/^\d{2}\.\d{2}\.\d{4}$/', $cell)) {
            $date = DateTime::createFromFormat('d.m.Y', $cell);
            $date->modify('-1 day');
            $cell = $date->format('d.m.Y');
        }
    }
}

不过这只是临时 workaround,只适用于特定格式的日期,不如前两种方法可靠。


内容的提问来源于stack exchange,提问作者Anton Trofimov

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.27 09:45:03