6

在 ColdFusion 11 中,我使用 cfSpreadsheet 将 .xls 文件转换为查询对象。这是我的演示电子表格的屏幕截图:

电子表格的屏幕截图

我使用此代码在创建查询对象后立即查看它:

<cfspreadsheet action="read" src="demo_spreadsheet.xls" 
       excludeHeaderRow="true" 
       headerrow="1" query="demo_query"/>
<cfdump var="#demo_query#">

...我得到了这些结果:

png 显示查询对象的转储

请注意,电子表格中的所有 4 位数年份现在都是 2 位数年份?当我使用以下代码输出查询对象中的数据时:

<ul>
<cfoutput query="demo_query">
    <li>#name# - #dateformat(start_date, 'medium')#</li>
</cfoutput>
</ul>

...我得到以下输出(好吧,我是新来的,所以我不能发布两个以上的屏幕截图,所以你必须相信我的复制/粘贴):

  • 阿尔法 - 2007 年 1 月 1 日
  • 布拉沃 - 1972 年 2 月 2 日
  • 查理 - 2017 年 3 月 3 日
  • 三角洲 - 1984 年 4 月 4 日
  • 回声 - 2029 年 12 月 31 日
  • 狐步舞 - 1930 年 1 月 1 日
  • 高尔夫 - 1930 年 1 月 1 日

1907 年现在是 2007 年,1917 年现在是 2017 年,1929 年现在是 2029 年,2030 年现在是 1930 年。似乎 1930 年 1 月 1 日之前的任何日期的年份被读作 20xx,而 2029 年 12 月 31 日之后的年份被读作19xx。

我错过了什么吗?我以为我们通过 Y2K 解决了这种问题。是否有一个我不正确的简单设置?我已经用谷歌搜索了这个问题,但我找不到任何关于它的信息。

任何建议都将受到欢迎。

4

1 回答 1

5

您的电子表格单元格很可能使用内置的区域格式*m/d/yy,这意味着显示的值(或在本例中为“读取”)可能会因使用的环境或客户端而异。

以星号 (*) 开头的日期和时间格式会响应控制面板中指定的区域日期和时间设置的更改。没有星号的格式不受控制面板设置的影响。

这似乎是 cfspreadsheet 正在发生的事情。不知道为什么 Excel 为 format 显示一个四位数的年份,而不是两位数*m/d/yy。但是,CF/POI 根据 Excel 规范返回正确的结果。请注意,如果您将单元格格式切换为非区域的四位数年份,即m/d/yyyy输出是您所期望的:

区域和非区域格式的比较 非区域日期格式

更新:至于为什么您的 CF 代码显示的年份与您预期的不同,这是由于 CF 处理模糊日期字符串的方式。需要注意的是,CFSpreadsheet 返回的查询包含字符串,而不是日期对象。当您将这些字符串传递给 时DateFormat,CF 必须首先解释这些字符串并将它们转换为日期对象,然后才能应用日期掩码。根据 CF 的规则,两位数的年份解释如下:

包含根据美国语言环境约定格式化的日期/时间值的字符串。可以表示 100 AD–9999 AD 范围内的日期/时间。0-29 年被解释为 2000-2029 年;30-99 年被解释为 1930-1999 年。

老实说,CFSpreadsheet 旨在提供一种简单的方式来读取和编写电子表格,而无需大量花里胡哨。AFAIK,它不支持更改单元格值的解释方式。如果要强制使用四位数年份,则必须手动或以编程方式将电子表格更改为使用非区域日期格式(即使用 CF 读取电子表格,并应用新的单元格格式)。这可能是最简单的选择。

如果您想在代码方面获得更大的灵活性,您还可以使用电子表格函数而不是 cfspreadsheet。尽管在这种特定情况下,我认为它们也缺乏必要的功能。因此,您可能会考虑使用底层 POI 库和一些 java 代码。该线程演示了如何获取有关电子表格单元格和值的各种详细信息。可以轻松修改它以构建您自己的查询或包含值、格式等的结构数组:

包含单元格数据的结构数组

代码:

<cfscript>
// get the sheet you want to read
cfSheet = SpreadSheetRead("c:/temp/demo_spreadsheet.xls"); 
workbook = cfSheet.getWorkBook();
sheetIndex = workbook.getActiveSheetIndex();
sheet = workbook.getSheetAt( sheetIndex );

// utility used to distinguish between dates and numbers
dateUtil = createObject("java", "org.apache.poi.ss.usermodel.DateUtil");

// process the rows and columns
rows = sheet.rowIterator();
while (rows.hasNext()) {
    currentRow = rows.next();
    data = {}; 

    cells = currentRow.cellIterator();
    while (cells.hasNext()) { 
        currentCell = cells.next();

        col = {};
        col.value  = "";
        col.type   = "";
        col.column = currentCell.getColumnIndex()+ 1;
        col.row    = currentCell.getRowIndex()+ 1;
        col.format = currentCell.getCellStyle().getDataFormatString();



        if (currentCell.getCellType() EQ currentCell.CELL_TYPE_STRING) {
               col.value = currentCell.getRichStringCellValue().getString();
            col.type = "string";
        }
        else if (currentCell.getCellType() EQ currentCell.CELL_TYPE_NUMERIC) {
            if (DateUtil.isCellDateFormatted(currentCell)) {
                 col.value = currentCell.getDateCellValue();
                 col.type = "date";
            } 
            else {
                 col.value = currentCell.getNumericCellValue();
                 col.type = "number";
            }
        }
        else if (currentCell.getCellType() EQ currentCell.CELL_TYPE_BOOLEAN) {
            col.value = currentCell.getBooleanCellValue();
            col.type = "boolean";
        }
        // ... handle other types CELL_TYPE_BLANK, CELL_TYPE_ERROR, CELL_TYPE_FORMULA

        data["COL"& col.column] = col;
    }

    // this row is finished. display all values
    WriteDump(data);
}
</cfscript>
于 2016-01-19T18:54:01.947 回答