Apache POI:从一个单元到另一个单元的传输时间
Apache POI: Transfer time from cell to cell
简而言之:我想将时间值从一个单元格复制到另一个单元格。
简而言之问题:POI 5.2.2(或更具体:DateUtil.internalGetExcelDate
)将 08:00 点从输入单元格转换为数值-1.00.
更多详情:有一个 xlsx 文件(使用 LibreOffice 7.0.4.2 创建),其中包含时间“08:00:00”:
我可以用 sourceCell.getLocalDateTimeCellValue()
读取那个值,这很好。
但是当我尝试将该值转移到另一个单元格 (targetCell.setCellValue(sourceCell.getLocalDateTimeCellValue())
) 时,在 targetCell
中存在值 -1 而不是预期的 08:00:00 o'时钟。
这是调试 setCellValue
调用时的屏幕截图:
下面是调试 DateUtil.internalGetExcelDate
调用时的屏幕截图:
可能的解决方法:我想它可以从 sourceCell
评估 LocalDateTime
并且如果它的年份 < 1904 那么我添加一些结果 LocalDateTime
没有被 DateUtil.internalGetExcelDate
.
转换为 -1.00 的年数
这是我不想做的事情,因为这会在 targetCell
中设置与 sourceCell
中不同的值。
另一种解决方法:另一种解决方法是使用 LocalDateTime.now()
,设置小时和分钟,调用 targetCell.setCellValue(...)
,然后像这样更改格式:
short format = workbook.createDataFormat().getFormat("HH:MM:SS");
CellStyle cellStyle = workbook.createCellStyle();
cellStyle.setDataFormat(format);
targetCell.setCellStyle(cellStyle);
不幸的是,我不知道 sourceCell
是只包含时间还是包含完整的时间戳。我只想复制单元格内容(适用于字符串、数字等)。
实际解决方法:作为当前(有效)解决方法,我检查年份,如果它小于 1900,那么我在该日期设置另一个年份,设置修改后的 LocalDateTime
到单元格中并设置数据格式(请参阅上面的解决方法描述)。
问题:如何将 LocalTime
值从一个单元格转移到另一个单元格(不处理年份)?我想我的(工作)解决方法不应该是答案......
Excel 单元格日期类型
Microsoft Excel 只有以下单元格数据类型:
- 字符串(字母数字)
- 数值(浮点数)
- 布尔值(真或假)
- Formula(公式字符串)
- 错误(内部错误代码)
- 空(空单元格)
没有特殊的日期单元格数据类型,也没有特殊的整数单元格日期类型。
Excel 如何存储日期或时间或 date-time
如果Excel存储date-time,它存储为浮点数。 1.00 是 1900-01-01 00:00:00.000。 (Excel设置1904-Date时有一个特例,但那只是1.00的意义的特例。)
加1.00就是加一天。增加 1/24 意味着增加一小时。增加 1/24/60 意味着增加一分钟。添加 1/24/60/60 意味着增加一秒。添加 1/24/60/60/10 表示添加十分之一秒,依此类推。
对于小于 1.00 的单元格值,Excel 将其解释为 1900 年第 1 个月第 0 天的时间(如果 Excel 已设置 1904 年日期,则为 1904 年)。 1/24 表示一小时。 1/24 + 1/24/60 表示一小时一分钟等等。所以你的 08:00:00 是单元格值 8*1/24 (8 小时) = 1/3.
读取 Excel 单元格值时,确定 Excel 将单元格值解释为日期或时间还是 date-time 的唯一方法是也获取单元格的数字格式。如果这是日期或时间或 date-time 格式,则 Excel 将单元格值 1.00 解释为 1900-01-01,将单元格值 1/24 解释为 01:00:00,单元格1/24 + 1/24/60 的值为 01:01:00 等等。
但你的观察是正确的。如果 Apache POI 从仅设置时间的 Excel 单元格读取 date-time,这是一个介于 0.00 和 1.00 之间的数字 (double
) 值,那么它会读取 date-time 1899-12-31 日。但这不是 Excel 所做的。对于 Excel,time-only 值在 1900 年第 1 个月的第 0 天。如果 Apache POI 设置 date-time 值,例如 1899-12-31 08:00:00 , 然后它设置 -1 因为 Excel 在 1900 之前不能有 date-time 值。
因此,在 Excel 单元格中设置时间值的唯一方法是将数字 (double
) 值设置在 0.00 和 1.00 之间,并设置数字格式为 [=13= 的单元格样式].不能仅从 Java date-time 值设置时间 Excel 单元格值,因为没有 Java date-time 值可以有一个月的第 0 天1 年 1900 年。
因此,如果 DateUtil.isCellDateFormatted 表明源单元格为日期格式且该单元格的数字 (double
) 单元格值小于 1,则设置该数字 (double
) 单元格值到新单元格并将该单元格的格式设置为与源单元格相同。
要测试的完整示例:
import java.io.FileInputStream;
import java.io.FileOutputStream;
import org.apache.poi.ss.usermodel.*;
public class ExcelSetCellValue {
public static void main(String[] args) throws Exception {
Workbook workbook = WorkbookFactory.create(new FileInputStream("./ExcelWithTime.xlsx")); String filePath = "./ExcelWithTimeNew.xlsx";
//Workbook workbook = WorkbookFactory.create(new FileInputStream("./ExcelWithTime.xls")); String filePath = "./ExcelWithTimeNew.xls";
Sheet sheet = workbook.getSheetAt(0);
Cell sourceCell = sheet.getRow(0).getCell(0); // get cell value from A1: 08:00:00
Row targetRow = sheet.getRow(5); if (targetRow==null) targetRow = sheet.createRow(5);
Cell targetCell = targetRow.getCell(5); if (targetCell==null) targetCell = targetRow.createCell(5);
if (sourceCell.getCellType() == CellType.NUMERIC && DateUtil.isCellDateFormatted(sourceCell)) {
System.out.println(sourceCell.getNumericCellValue()); // 8*1/24 = 1/3
System.out.println(sourceCell.getLocalDateTimeCellValue()); // 1899-12-31T08:00
//targetCell.setCellValue(sourceCell.getLocalDateTimeCellValue()); // does not work because sourceCell.getLocalDateTimeCellValue() is in year 1899
targetCell.setCellValue(sourceCell.getNumericCellValue());
targetCell.setCellStyle(sourceCell.getCellStyle());
}
FileOutputStream out = new FileOutputStream(filePath);
workbook.write(out);
out.close();
workbook.close();
}
}
简而言之:我想将时间值从一个单元格复制到另一个单元格。
简而言之问题:POI 5.2.2(或更具体:DateUtil.internalGetExcelDate
)将 08:00 点从输入单元格转换为数值-1.00.
更多详情:有一个 xlsx 文件(使用 LibreOffice 7.0.4.2 创建),其中包含时间“08:00:00”:
我可以用 sourceCell.getLocalDateTimeCellValue()
读取那个值,这很好。
但是当我尝试将该值转移到另一个单元格 (targetCell.setCellValue(sourceCell.getLocalDateTimeCellValue())
) 时,在 targetCell
中存在值 -1 而不是预期的 08:00:00 o'时钟。
这是调试 setCellValue
调用时的屏幕截图:
下面是调试 DateUtil.internalGetExcelDate
调用时的屏幕截图:
可能的解决方法:我想它可以从 sourceCell
评估 LocalDateTime
并且如果它的年份 < 1904 那么我添加一些结果 LocalDateTime
没有被 DateUtil.internalGetExcelDate
.
这是我不想做的事情,因为这会在 targetCell
中设置与 sourceCell
中不同的值。
另一种解决方法:另一种解决方法是使用 LocalDateTime.now()
,设置小时和分钟,调用 targetCell.setCellValue(...)
,然后像这样更改格式:
short format = workbook.createDataFormat().getFormat("HH:MM:SS");
CellStyle cellStyle = workbook.createCellStyle();
cellStyle.setDataFormat(format);
targetCell.setCellStyle(cellStyle);
不幸的是,我不知道 sourceCell
是只包含时间还是包含完整的时间戳。我只想复制单元格内容(适用于字符串、数字等)。
实际解决方法:作为当前(有效)解决方法,我检查年份,如果它小于 1900,那么我在该日期设置另一个年份,设置修改后的 LocalDateTime
到单元格中并设置数据格式(请参阅上面的解决方法描述)。
问题:如何将 LocalTime
值从一个单元格转移到另一个单元格(不处理年份)?我想我的(工作)解决方法不应该是答案......
Excel 单元格日期类型
Microsoft Excel 只有以下单元格数据类型:
- 字符串(字母数字)
- 数值(浮点数)
- 布尔值(真或假)
- Formula(公式字符串)
- 错误(内部错误代码)
- 空(空单元格)
没有特殊的日期单元格数据类型,也没有特殊的整数单元格日期类型。
Excel 如何存储日期或时间或 date-time
如果Excel存储date-time,它存储为浮点数。 1.00 是 1900-01-01 00:00:00.000。 (Excel设置1904-Date时有一个特例,但那只是1.00的意义的特例。)
加1.00就是加一天。增加 1/24 意味着增加一小时。增加 1/24/60 意味着增加一分钟。添加 1/24/60/60 意味着增加一秒。添加 1/24/60/60/10 表示添加十分之一秒,依此类推。
对于小于 1.00 的单元格值,Excel 将其解释为 1900 年第 1 个月第 0 天的时间(如果 Excel 已设置 1904 年日期,则为 1904 年)。 1/24 表示一小时。 1/24 + 1/24/60 表示一小时一分钟等等。所以你的 08:00:00 是单元格值 8*1/24 (8 小时) = 1/3.
读取 Excel 单元格值时,确定 Excel 将单元格值解释为日期或时间还是 date-time 的唯一方法是也获取单元格的数字格式。如果这是日期或时间或 date-time 格式,则 Excel 将单元格值 1.00 解释为 1900-01-01,将单元格值 1/24 解释为 01:00:00,单元格1/24 + 1/24/60 的值为 01:01:00 等等。
但你的观察是正确的。如果 Apache POI 从仅设置时间的 Excel 单元格读取 date-time,这是一个介于 0.00 和 1.00 之间的数字 (double
) 值,那么它会读取 date-time 1899-12-31 日。但这不是 Excel 所做的。对于 Excel,time-only 值在 1900 年第 1 个月的第 0 天。如果 Apache POI 设置 date-time 值,例如 1899-12-31 08:00:00 , 然后它设置 -1 因为 Excel 在 1900 之前不能有 date-time 值。
因此,在 Excel 单元格中设置时间值的唯一方法是将数字 (double
) 值设置在 0.00 和 1.00 之间,并设置数字格式为 [=13= 的单元格样式].不能仅从 Java date-time 值设置时间 Excel 单元格值,因为没有 Java date-time 值可以有一个月的第 0 天1 年 1900 年。
因此,如果 DateUtil.isCellDateFormatted 表明源单元格为日期格式且该单元格的数字 (double
) 单元格值小于 1,则设置该数字 (double
) 单元格值到新单元格并将该单元格的格式设置为与源单元格相同。
要测试的完整示例:
import java.io.FileInputStream;
import java.io.FileOutputStream;
import org.apache.poi.ss.usermodel.*;
public class ExcelSetCellValue {
public static void main(String[] args) throws Exception {
Workbook workbook = WorkbookFactory.create(new FileInputStream("./ExcelWithTime.xlsx")); String filePath = "./ExcelWithTimeNew.xlsx";
//Workbook workbook = WorkbookFactory.create(new FileInputStream("./ExcelWithTime.xls")); String filePath = "./ExcelWithTimeNew.xls";
Sheet sheet = workbook.getSheetAt(0);
Cell sourceCell = sheet.getRow(0).getCell(0); // get cell value from A1: 08:00:00
Row targetRow = sheet.getRow(5); if (targetRow==null) targetRow = sheet.createRow(5);
Cell targetCell = targetRow.getCell(5); if (targetCell==null) targetCell = targetRow.createCell(5);
if (sourceCell.getCellType() == CellType.NUMERIC && DateUtil.isCellDateFormatted(sourceCell)) {
System.out.println(sourceCell.getNumericCellValue()); // 8*1/24 = 1/3
System.out.println(sourceCell.getLocalDateTimeCellValue()); // 1899-12-31T08:00
//targetCell.setCellValue(sourceCell.getLocalDateTimeCellValue()); // does not work because sourceCell.getLocalDateTimeCellValue() is in year 1899
targetCell.setCellValue(sourceCell.getNumericCellValue());
targetCell.setCellStyle(sourceCell.getCellStyle());
}
FileOutputStream out = new FileOutputStream(filePath);
workbook.write(out);
out.close();
workbook.close();
}
}