excel – cfSpreadsheet两位数年份

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

screenshot of spreadsheet

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

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

……我得到了这些结果:

png showing dump of query object

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

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

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

> Alpha – 2007年1月1日
>布拉沃 – 1972年2月2日
>查理 – 2017年3月3日
>达美 – 1984年4月4日
> Echo – 2029年12月31日
> Foxtrot – 1930年1月1日
>高尔夫 – 1930年1月1日

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

我错过了什么吗?我以为我们用Y2K想出了这种事情.在某处我有不正确的简单设置吗?我已经用Google搜索了这个问题,我找不到任何相关信息.

任何建议都是最受欢迎的.

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

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规范返回正确的结果.请注意,如果您将单元格格式切换为非区域四位数年份,即m / d / yyyy,则输出符合您的预期:

Comparison of regional and non-regional formats
Non-regional Date Format

更新:至于为什么您的CF代码显示的年份与您预期的不同,这是由于CF处理的日期字符串有多么模糊.需要注意的是,CFSpreadsheet返回的查询包含字符串,而不是日期对象.将这些字符串传递给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,它不支持更改单元格值的解释方式.如果要强制使用四位数年份,则必须手动或以编程方式更改电子表格以使用非区域日期格式(即,使用CF读取电子表格,然后应用新的单元格格式).这可能是最简单的选择.

如果您想要更灵活的代码,您也可以使用spreadsheet functions而不是cfspreadsheet.虽然在这种特殊情况下,我认为他们也缺乏必要的功能.因此,您可能会考虑使用底层POI库和一些Java代码. This thread演示了如何获取有关电子表格单元格和值的各种详细信息.可以很容易地修改它来构建自己的查询或包含值,格式等的结构数组:

Array of structures containing cell data

码:

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

转载注明原文:excel – cfSpreadsheet两位数年份 - 代码日志