java - POI - 在 Excel 和 Java 日期之间转换的问题,反之亦然

标签 java excel apache-poi

我正在尝试使用 Apache POI (4.0.1) 在 Excel 工作簿的单元格中节省时间。

我将时间转换为 java.util.Date然后尝试使用 org.apache.poi.ss.usermodel.DateUtil.getExcelDate方法然后将其保存在单元格中。

我发现由于时间与纪元(1899 年)在同一年,getExcelDate 中有一个硬编码检查。这禁止将日期转换为 1900 年之前的年份,从而阻止我做我想做的事情。

示例应用:

import java.util.Date;
import java.util.stream.DoubleStream;
import org.apache.poi.ss.usermodel.DateUtil;

public class POIQuery {
    public static void main(final String[] args) {
    final String format = "%-20s%-35s%-20s%n"; //$NON-NLS-1$

    System.out.format(format, "Input Excel Date", "Java Date", "Converted Excel Date");

    DoubleStream.of(0, 0.5d, 1.5d).forEach(excelDate -> {
        final Date date = DateUtil.getJavaDate(excelDate);
        System.out.format(format, excelDate, date, DateUtil.getExcelDate(date));
    });
    }
}

输出(注意,根据文档 - “-1”的“转换的 Excel 日期”表示错误)。
Input Excel Date    Java Date                          Converted Excel Date
0.0                 Sun Dec 31 00:00:00 GMT 1899       -1.0                
0.5                 Sun Dec 31 12:00:00 GMT 1899       -1.0                
1.5                 Mon Jan 01 12:00:00 GMT 1900       1.5

在这里你可以看到我要求的是代表 Excel 日期“0.5”的 Java 日期。
然后我使用提供的 Java 日期,但 POI 说没有对应的 Excel 日期 - 即使我已经从中生成了它。

我错过了什么……?

最佳答案

Excel 1900 年日期系统中的日期值从值 0 = 1900 年 1 月的第 0 天开始。没有 Excel之前的日期值。

如果您在 Excel 中有以下单元格:

     A                  B
1  Value      Excel date
2      0      01/00/1900 00:00:00
3    0.5      01/00/1900 12:00:00
4      1      01/01/1900 00:00:00
5    1.5      01/01/1900 12:00:00

其中 B 列中的值与 A 列中的值相同但使用数字格式 MM/DD/YYYY hh:mm:ss 格式化为日期,你看。

所以没有Excel日期为 1899 年 12 月 31 日。这就是为什么 DateUtil.getExcelDate(date) date 时失败是 Java日期Sun Dec 31 00:00:00 GMT 1899Sun Dec 31 12:00:00 GMT 1899 .

但是DateUtil.getJavaDate(excelDate)excelDate 时返回 1899 年 12 月 31 日是 double来自 0.0 的值至0.999... .那是因为没有Java日期 1900 年 1 月 0 日可能。但是有Excel日期值可能来自 0.00.999... .

换句话说,Excel来自 0.0 的日期值至0.999...是实际时间值之前 Excel 中第一个可能的一整天,即 1900 年 1 月 1 日的日期。它们实际上不是在一天中,而是在第 0 天。

0.0 开始的日期值至0.999...并转换 Java 1899 年 12 月 31 日是特殊情况,可以这样处理。

通过扩展您的代码:
import java.util.Date;
import java.util.Calendar;
import java.util.stream.DoubleStream;
import org.apache.poi.ss.usermodel.DateUtil;

public class POIQuery {
    public static void main(final String[] args) {
    final String format = "%-20s%-35s%-20s%n"; //$NON-NLS-1$

    System.out.format(format, "Input Excel Date", "Java Date", "Converted Excel Date");

    DoubleStream.of(0, 0.5d, 1d, 1.5d, 44000d, 44000.5d).forEach(excelDate -> {
        final Date date = DateUtil.getJavaDate(excelDate);
        Calendar cal = Calendar.getInstance();
        cal.setTime(date);
        double excelDateFromDate = -1d;
        if (cal.get(Calendar.YEAR) == 1899 && cal.get(Calendar.MONTH) == 11 && cal.get(Calendar.DATE) == 31) {
         cal.add(Calendar.DATE, 1);
         excelDateFromDate = DateUtil.getExcelDate(cal.getTime());
         excelDateFromDate -= 1d; 
        } else {
         excelDateFromDate = DateUtil.getExcelDate(date);
        }
        System.out.format(format, excelDate, date, excelDateFromDate);
    });
    }
}

如果转换为 Java日期是 1899 年 12 月 31 日,我们知道这是从 Excel 转换而来的。 , 然后在将其重新转换为 Excel日期值,使用前先加一天DateUtil.getExcelDate .所以DateUtil.getExcelDate从 1900 年 1 月 1 日开始转换。然后减去 1来自 DateUtil.getExcelDate 的结果.

关于java - POI - 在 Excel 和 Java 日期之间转换的问题,反之亦然,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60568161/

相关文章:

android-studio - 无法使用 Apache POI 库运行 Android Studio 项目

Java - 从 22050 降采样到 8000 给出零字节

Excel 根据另一列计算值的数量

java - 监控不同java对象的内存消耗

Excel:使用数组公式搜索特定字符串中的字符串列表?

excel - 使用列号计算列中数字的平均值

java - 如何保存从 Java 创建的 Excel 文档

java - 写入Excel文件后抛出文件未找到异常

java - 如何正确同步多个线程访问的列表?

java - 查找多个列表的最大值