在 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>
...我得到以下输出(好吧,我是新来的,所以我不能发布两个以上的屏幕截图,所以你必须相信我的复制/粘贴):
- Alpha 版 - 2007 年 1 月 1 日
- Bravo - 1972 年 2 月 2 日
- 查理 - 2017 年 3 月 3 日
- 达美航空 - 1984 年 4 月 4 日
- Echo - 2029 年 12 月 31 日
- 狐步舞 - 1930 年 1 月 1 日
- 高尔夫 - 1930 年 1 月 1 日
1907 年现在是 2007 年,1917 年现在是 2017 年,1929 年现在是 2029 年,2030 年现在是 1930 年。看来 1930 年 1 月 1 日之前的任何日期的年份都被读取为 20xx,2029 年 12 月 31 日之后的任何日期的年份都被读取为 20xx读作 19xx。
我错过了什么吗?我以为我们在千年虫问题上就解决了这个问题。是否有一个简单的设置我不正确?我用谷歌搜索了这个问题,但找不到任何相关信息。
非常欢迎任何建议。
最佳答案
您的电子表格单元格很可能正在使用内置的 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
,则输出将是您所期望的:
更新:至于为什么您的 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而不是 cf 电子表格。尽管在这种具体情况下,我认为它们也缺乏必要的功能。因此,您可能会考虑使用底层 POI 库和一些 java 代码。 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>
关于excel - cfSpreadsheet 2 位数年份,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34882005/