Java转换';Excel日期序列号';至';日期时间';

Java转换';Excel日期序列号';至';日期时间';,java,excel,datetime,Java,Excel,Datetime,如何使用Java将“excel日期序列号”(即33257.41597222225)转换为日期时间(即19/01/1991 09:59:00)?您还可以查看方法DateUtils#getLocalDateTime(双日期,布尔使用1904窗口,布尔舍入秒)。此实用程序类为使用Excel日期提供了更方便的方法。Excel将日期和时间存储为一个数字,表示从那时起的天数,加上24小时工作日的小数部分:ddddd.tttttttt 这称为序列日期或序列日期时间 来自微软的链接文档似乎非常清晰。 MS表示:

如何使用Java将“excel日期序列号”(即33257.41597222225)转换为日期时间(即19/01/1991 09:59:00)?

您还可以查看方法
DateUtils#getLocalDateTime(双日期,布尔使用1904窗口,布尔舍入秒)
。此实用程序类为使用Excel日期提供了更方便的方法。

Excel将日期和时间存储为一个数字,表示从那时起的天数,加上24小时工作日的小数部分:
ddddd.tttttttt

这称为序列日期或序列日期时间

来自微软的链接文档似乎非常清晰。

MS表示:

Excel将日期存储为连续序列号,以便在计算中使用。 默认情况下,1900年1月1日是序列号1,2008年1月1日是序列号39448,因为它是1900年1月1日之后的39447天

好吧,我要检查一下这个声明:

LocalDate testDate = LocalDate.of(1900, Month.JANUARY, 1).plusDays(39447);
System.out.println(testDate);// prints 2008-01-02
1900年1月1日后的39447天确实。。。2008年1月2日

这是为什么?

Excel中的日期由一个纪元(1899年12月30日或1900年1月1日或1904年1月1日…)开始的天数表示,这只是故事的一部分

我在这里找到了一个最终的答案:(某个上帝或任何可能保佑这些家伙的人)

在Excel中实现日期例程的开发人员故意引入了一个bug,以便与来自的同一已知问题兼容

他们将1900年视为闰年,但不是, 因此,任何超过1900年1月28日的日期都比实际日期多一天。

这就是为什么Excel认为2008年1月1日用数字39448表示:因为1900年1月0日之后是39448个单位(是的,Excel认为零)——即39447天加1900年1月29日

Excel还可以将序列日期的日期部分视为自1904年1月0日起的天数;此模式称为1904模式或1904系统,用于与Macintosh系统兼容

因为Excel日期不携带任何时区信息——它只是一个数字——所以最好使用Java类,如/来表示没有时区信息的值

实际上,对于现在的日期,人们可能认为从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;
    }
}

很接近,但这只是日期,而不是时间@Ivan@K.Dᴀᴠɪs java
Date
对象同时存储日期和时间。如果您谈论的是字符串表示,那么在
SimpleDateFormat
中使用适当的格式将解决这个问题,感谢您的澄清-不熟悉Java@Ivan。这为我节省了大量代码(并且非常适合我的用例)
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