Excel 将日期和时间存储为一个数字,表示自 January 0, 1900 以来的天数,加上一天 24 小时的小数部分:ddddd.tttttt。
这称为序列日期或序列日期时间。
微软的链接文档似乎很清楚。
MS DATEVALUE function 状态:
Excel 将日期存储为连续的序列号,以便在计算中使用它们。
默认情况下,1900 年 1 月 1 日是序列号 1,而 2008 年 1 月 1 日是序列号 39448,因为它是 1900 年 1 月 1 日之后的 39,447 天
好吧,我要检查一下这个声明:
LocalDate testDate = LocalDate.of(1900, Month.JANUARY, 1).plusDays(39447);
System.out.println(testDate);// prints 2008-01-02
在1900 年 1 月 1 日之后的 39,447 天确实是……2008 年 1 月 2 日!
这是为什么呢?
Excel 中的日期表示为从一个纪元(1899 年 12 月 30 日或 1900 年 1 月 1 日或 1904 年...)开始的天数,这只是故事的一部分.
我在这里找到了终极答案:Dates And Times In Excel(某位神或任何可能保佑这些人的人)。
在 Excel 中实现日期例程的开发人员故意引入了一个错误,以便与来自 Lotus 1-2-3 的同一已知问题兼容。
他们将 1900 年视为闰年,但不是,
因此,任何超过 1900 年 2 月 28 日的日期都比实际日期多一天。
这就是为什么 Excel 认为 2008 年 1 月 1 日 由数字 39448 表示:因为它在 1900 年 1 月 0 日之后是 39,448 个单位 (是的,Excel 认为 0)- 即 39,447 天 加上 1900 年 2 月 29 日。
Excel 还可以将序列日期的日期部分视为自 1904 年 1 月 0 日以来的天数;此模式称为 1904-mode 或 1904-system,用于与 Macintosh 系统兼容。
由于 Excel 日期不包含任何时区信息 - 它只是一个数字 - 最好使用 Java 类,如 LocalDate/LocalDateTime 来表示没有时区信息的此类值。
嗯,在实践中 - 对于现在的日期 - 人们可能会认为 Excel 纪元从 1900 年 12 月 30 日开始 但事实并非如此。
Excel 演示 - 日期格式为 dd/mm/yyyy hh:MM:ss
日期作为左边的数字插入
适合所需转换的类:
public class SerialDate {
//days from 1899-12-31 to Instant.EPOCH (1970-01-01T00:00:00Z)
public static final long EPOCH = -25568L;
private long serialDays;
private double serialTime;
private long epochDays;
private long daySeconds;
/**
* @param date number of Excel-days since <i>January 0, 1899</i>
*/
public SerialDate(long date) {
serialDays = date;
if (date > 59)//Lotus123 bug
--date;
epochDays = EPOCH + date;
}
/**
* @param date number of days since <i>January 0, 1899</i> with a time fraction
*/
public SerialDate(double date) {
this((long)date);
serialTime = date - serialDays;
daySeconds = Math.round(serialTime * 24 * 60 * 60);
}
/**
* @return days since 1970-01-01
*/
public long toEpochDays() {
return epochDays;
}
/**
* @return seconds of the day for this SerialDate
*/
public long toDaySeconds() {
return daySeconds;
}
/**
* @return a value suitable for an Excel date
*/
public double getSerialDate() {
return serialTime + serialDays;
}
}
使用示例:
SerialDate sd = new SerialDate(33257.415972222225);
LocalDateTime dt = LocalDateTime.of(
LocalDate.ofEpochDay(sd.toEpochDays()),
LocalTime.ofSecondOfDay(sd.toDaySeconds()));
System.out.println(dt);//prints 1991-01-19T09:59