如何使用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
,但我使用的是BigDecimal
。 BigDecimal
类的速度慢但准确,而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.Date
,Calendar
和SimpleDateFormat
。现在位于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 8,Java SE 9,Java SE 10,Java SE 11和更高版本-具有捆绑实现的标准Java API的一部分。
Java 9添加了一些次要功能和修复。
Java SE 6和Java 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中添加内容提供了一个试验场。您可能会在这里找到一些有用的类,例如
Interval
,YearWeek
,YearQuarter
和more。