cfSpreadsheet 2 位数年份

cfSpreadsheet 2-digit years

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

我用这段代码一创建就看到了查询对象:

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

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

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

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

...我得到以下输出(好的,我是新来的,所以我不能 post 超过两个屏幕截图所以你必须相信我 copy/paste):

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

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

非常欢迎任何建议。

很可能您的电子表格单元格正在使用内置的 regional format *m/d/yy,这意味着显示的值(或在本例中为 "read")可能会因所使用的环境或客户端而异。

Date and time formats that begin with an asterisk (*) respond to changes in regional date and time settings that are specified in Control Panel. Formats without an asterisk are not affected by Control Panel settings.

cfspreadsheet 似乎就是这样。不确定为什么 Excel 显示 四位 数字年份,而不是两位数字,格式 *m/d/yy。但是,CF/POI 根据 Excel 规范返回正确的结果。请注意,如果您将单元格格式切换为 non-regional,四位数年份,即 m/d/yyyy 输出是您所期望的:

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

A string containing a date/time value formatted according to U.S. locale conventions. Can represent a date/time in the range 100 AD–9999 AD. Years 0-29 are interpreted as 2000-2029; years 30-99 are interpreted as 1930-1999.

老实说,CFSpreadsheet 旨在提供一种简单的方式来读取和写入电子表格,而且没有很多附加功能。 AFAIK,它不支持更改单元格值的解释方式。如果要强制使用四位数年份,则必须手动或以编程方式更改电子表格以使用 non-regional 日期格式(即使用 CF 读取电子表格,并应用新的单元格格式)。这可能是最简单的选择。

如果您希望在代码方面有更大的灵活性,您还可以使用spreadsheet functions instead of cfspreadsheet. Though in this specific case, I think they too lack the necessary features. So you might look into using the underlying POI library and a bit of java code. This thread演示如何获取有关电子表格单元格和值的各种详细信息。它可以很容易地修改以构建您自己的查询或包含值、格式等的结构数组:

代码:

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