我在Excel中有一个日期列,但是当我在我的Java应用程序中读取它时,得到的值是数字。
例子
Excel日期
1/1/2013
我正在理解它
41275.00
如何在我的Java应用程序中将数字转换为日期?
以下是将Excel日期转换为Java日期的最小工作示例:
Date javaDate= DateUtil.getJavaDate((double) 41275.00);
System.out.println(new SimpleDateFormat("MM/dd/yyyy").format(javaDate));
返回
01/01/2013
您还需要导入以下包:
java.text.SimpleDateFormat
java.util.Date
java.util.Date
、java.util.Calendar
和java.text.SimpleDateFormat
这样的旧日期时间类现在已经成为遗留系统,被内置于Java 8及更高版本中的java.time类所取代。请参阅Oracle的教程。 - Basil Bourque使用现代的java.time类。
LocalDate // Represent a date-only vaule, without time-of-day and without time zone.
.of( 1899 , Month.DECEMBER , 30 ) // Specify epoch reference date used by *some* versions of Excel. Beware: Some versions use a 1904 epoch reference. Returns a `LocalDate` object.
.plusDays( // Add a number of days.
(long) Double.parseDouble( "41275.00" ) // Get a number of whole days from your input string.
) // Returns another instance of a `LocalDate`, per Immutable Objects pattern, rather than altering the original.
.toString() // Generate text representing the value of this `LocalDate` in standard ISO 8601 format.
final static public LocalDate EXCEL_EPOCH_REFERENCE =
LocalDate.of( 1899 , Month.DECEMBER , 30 )
; // Beware: Some versions of Excel use a 1904 epoch reference.
将输入字符串解析为BigDecimal
以获取更高的精度(相对于浮点类型,后者为了更快的执行而牺牲了精度)。
BigDecimal countFromEpoch = new BigDecimal( "41275.00" );
将整天数添加到纪元参考日期。
long days = countFromEpoch.longValue(); // Extract the number of whole days, dropping the fraction.
LocalDate localDate = EXCEL_EPOCH_REFERENCE.plusDays( days );
localDate.toString(): 2013-01-01
本地日期.toString():2013-01-01
java.time框架已内置于Java 8及更高版本中。这些类替代了老旧的legacy日期时间类,如java.util.Date
、Calendar
和SimpleDateFormat
。
欲了解更多信息,请参阅Oracle教程。同时在Stack Overflow上搜索许多示例和解释。规范为JSR 310。
Joda-Time项目现在处于维护模式,建议迁移到java.time类。
您可以直接与数据库交换java.time对象。使用符合JDBC 4.2或更高版本的JDBC驱动程序。不需要字符串,也不需要java.sql.*
类。Hibernate 5和JPA 2.2支持java.time。
如何获取java.time类?
Apache POI提供了一些工具来处理日期,详见http://poi.apache.org/apidocs/org/apache/poi/ss/usermodel/DateUtil.html,尤其是http://poi.apache.org/apidocs/org/apache/poi/ss/usermodel/DateUtil.html#getJavaDate(double)
注意,Excel将日期存储为自1900年起的天数(加上小数天数),有些情况下可能是自1904年起。请参考http://support.microsoft.com/kb/180162。
ddddd.tttttt
。这被称为序列日期或序列日期时间。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年...)开始计数的天数,这只是故事的一部分。
我在这里找到了一个终极答案:Excel中的日期和时间(某个神祇或任何人都可以保佑这些家伙)。
在实现Excel日期例程的开发人员为了与Lotus 1-2-3的相同已知问题兼容而故意引入了一个错误。
他们将1900年视为闰年,但它并不是闰年,所以任何超过1900年1月28日的日期都比实际日期多一天。
LocalDate
/LocalDateTime
来表示这些值而不包含时区信息。
实际上,对于现在的日期来说,人们可以从1900年12月30日开始计算Excel时代,但事实并非如此。
Excel演示 - 日期格式为dd/mm/yyyy
日期以左侧的数字形式插入
适合所需转换的类:
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;
}
}
使用示例:
LocalDate dt = LocalDate.ofEpochDay(new SerialDate(41275).toEpochDays());
System.out.println(dt);//prints 2013-01-01
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
Excel 序列化日期是自 1900 年 1 月 1 日以来的天数。为了再次确定日期,我们必须添加相应数量的连续编号天数。
对于 Java 8 而言,不需要任何依赖项。
```
/*
1900-1-0 0
1900-1-1 1
1900-1-2 2
1900-1-3 3
*/
int days = 43323;
LocalDate start = LocalDate.of(1900, 1, 1);
LocalDate today = LocalDate.of(2018, 8, 11);
// days to date
LocalDate date = start.plusDays(days).minusDays(2);
System.out.println(date);
// date to days
long days1 = ChronoUnit.DAYS.between(start, today) + 2;
System.out.println(days1);
```
// somewhere as double static
LocalDateTime EXCEL_START = LocalDateTime.of(1899, 12, 30, 0, 0);
Double doubleValue = 44705.416666666664; // input
long days = doubleValue.longValue();
long seconds = Math.round((doubleValue - days) * 24 * 60 * 60);
LocalDateTime converted = EXCEL_START
.plusDays(days)
.plusSeconds(seconds); //2022-05-24T10:00