我有 Java 时间(自 1970 年 1 月 1 日以来的毫秒数)并且想将该时间写入 csv 文件,以便 Excel 可以正确解释和格式化它。我知道,excel 使用“序列日期时间”作为格式 - 这是一个浮点数,其中整数部分给出自 1900 年 1 月 1 日以来的天数,小数部分给出一天的小数部分。
我无法理解时区和夏令时处理。
这个页面说 excel 纪元(1/1/1900)基于本地(=创建 Excel 文件的计算机?)时区。这意味着如果没有计算机时区创建它的信息,序列日期并不表示唯一的时间瞬间。不是我会选择的,但是好的。
现在接受这一点,我相信我可以通过以下 Java 代码将 Java 时间转换为 Excel 序列日期(nb:我在苏黎世,CET 时区):
private static final long ONE_HOUR= 60L * 60 * 1000;
private static final long ONE_DAY = 24 * ONE_HOUR;
private static final long excelEpoch; 
static{
    Calendar cal;
    cal = Calendar.getInstance(TimeZone.getTimeZone("Europe/Zurich"));
    cal.set(Calendar.YEAR, 1900);
    cal.set(Calendar.DAY_OF_YEAR, 1);
    cal.set(Calendar.HOUR_OF_DAY, 0);
    cal.set(Calendar.MINUTE, 0);
    cal.set(Calendar.SECOND, 0);
    cal.set(Calendar.MILLISECOND, 0);
    excelEpoch = cal.getTimeInMillis();
}
private static String formatForExcel(long time){
    return ""+(time-excelEpoch)/(double)ONE_DAY;
}
使用它我可以打印几次:
public static void main(String[] args) {
    String sep = "\t"; // csv field separator
    SimpleDateFormat fmt = new SimpleDateFormat("HH:mm:ss d/M/yyyy");       
    fmt.setTimeZone(TimeZone.getTimeZone("Europe/Zurich"));
    System.out.println("Time in ms since 1/1/1970 UTC"+ sep + "Time as string" + sep + "Excel serial" + sep + "Excel serial formatted by excel");
    long startTime = 1332630000000L; // 25/3/2012 00:00 CET , shortly before change from winter time to DST
    for (long t = startTime;  t < startTime + 4*ONE_HOUR; t+=ONE_HOUR) {
        System.out.println(t + sep + fmt.format(new Date(t)) + sep + formatForExcel(t) + sep + formatForExcel(t));
    }
}
哪个返回
Time in ms since 1/1/1970 UTC   Time as string  Excel serial    Excel serial formatted by excel
1332630000000   00:00:00 25/3/2012  40991.0 40991.0
1332633600000   01:00:00 25/3/2012  40991.041666666664  40991.041666666664
1332637200000   03:00:00 25/3/2012  40991.083333333336  40991.083333333336
1332640800000   04:00:00 25/3/2012  40991.125   40991.125
请注意,从冬季时间到 DST 的变化发生在这些时间(检查第二列,缺少第 2 小时)。
现在是混乱。如果我将其粘贴到 excel 中,并为最后一列选择“格式化单元格...”,然后选择“时间”(任何格式),它会打印:
Time in ms since 1/1/1970 UTC   Time as string  Excel serial    Excel serial formatted by excel
1332630000000   25.03.2012 00:00    40991   0:00:00
1332633600000   25.03.2012 01:00    40991.04167 1:00:00
1332637200000   25.03.2012 03:00    40991.08333 2:00:00
1332640800000   25.03.2012 04:00    40991.125   3:00:00
请注意,格式化序列日期的 excel 不会更改为 DST。所以这不是挂钟时间。
长话短说:
我应该如何将 Java 时间转换为 Excel 才能正常工作?