如何使用Java将'excel日期序列号'(即33257.415972222225)转换为DateTime(即19/01/1991 09:59:00)?

最佳答案

时代参考日期

根据this documentation,来自Microsoft Excel的值是自epoch reference中1900-01-01的UTC以来的天数。在内部,实际的参考日期为this Wikipedia page上记载的1899年12月30日。

请注意,Excel use a different epoch in 1904的某些版本(macOS的旧版本?)。

在代码中的某个地方建立纪元引用。

final static public LocalDate EXCEL_EPOCH_REFERENCE =
    LocalDate.of( 1899 , Month.DECEMBER , 30 )
; // Beware: Some versions of Excel use a 1904 epoch reference.


算一算。我们分两个步骤进行。

首先获取没有日期的仅日期部分。从输入的数字中提取整个天数,然后添加到纪元参考日期。

其次,我们提取分数并将其用于计算一个24小时通用天的一部分。我们得到一天中的纳秒总数,然后乘以分数。我认为Excel可能以毫秒为单位,但是我认为这并不重要,尤其是如果您希望在结果中舍入小数秒,如下所示。

最后,我们以UTC形式获取日期的第一刻,并添加一天中该部分的纳秒数。这将返回一个OffsetDateTime对象。

您可能在此代码中也可以使用double / Double,但我使用的是BigDecimalBigDecimal类的速度慢但准确,而floating-point类型的速度快但不准确。

BigDecimal countFromEpoch = new BigDecimal( "33257.415972222225" );

// Date portion
long days = countFromEpoch.longValue();
LocalDate localDate = EXCEL_EPOCH_REFERENCE.plusDays( days );

// Time-of-day portion
BigDecimal fraction = countFromEpoch.subtract( new BigDecimal( days ) );
long nanos = fraction.multiply( new BigDecimal( TimeUnit.DAYS.toNanos( 1 ) ) ).longValue(); // Get the number of nanoseconds in a day, and multiply our decimal fraction.

OffsetDateTime odt = OffsetDateTime.of( localDate , LocalTime.MIN , ZoneOffset.UTC ).plusNanos( nanos ) ;



  odt.toString():1991-01-19T09:59:00.000000240Z


您可能需要截断小数秒。

OffsetDateTime odt =
    OffsetDateTime
    .of( localDate , LocalTime.MIN , ZoneOffset.UTC )
    .plusNanos( nanos )
    .truncatedTo( ChronoUnit.SECONDS )
;



  odt.toString():1991-01-19T09:59Z




关于java.time

java.time框架内置于Java 8及更高版本中。这些类取代了麻烦的旧legacy日期时间类,例如java.util.DateCalendarSimpleDateFormat

现在位于Joda-Time中的maintenance mode项目建议迁移到java.time类。

要了解更多信息,请参见Oracle Tutorial。并在Stack Overflow中搜索许多示例和说明。规格为JSR 310

您可以直接与数据库交换java.time对象。使用与JDBC driver或更高版本兼容的JDBC 4.2。不需要字符串,不需要java.sql.*类。

在哪里获取java.time类?


Java SE 8Java SE 9Java SE 10Java SE 11和更高版本-具有捆绑实现的标准Java API的一部分。


Java 9添加了一些次要功能和修复。

Java SE 6Java SE 7


大多数java.time功能都被反向移植到ThreeTen-Backport中的Java 6和7。

Android


更高版本的Android捆绑了java.time类的实现。
对于早期的Android(ThreeTenABP项目改编为ThreeTen-Backport(如上所述)。请参见How to use ThreeTenABP…



ThreeTen-Extra项目使用其他类扩展了java.time。该项目为将来可能在java.time中添加内容提供了一个试验场。您可能会在这里找到一些有用的类,例如IntervalYearWeekYearQuartermore

09-17 01:11
查看更多