Java:如何将LocalDateTime值转换为日期并保留时间部分

时间:2018-07-19 13:34:01

标签: java java-8

我需要从具有日期和时间两个部分的LocalDateTime转换为Date而又不损失时间部分。我一直在做类似的事情:

LocalDateTime ldt = //some full date-time value

Date date = java.util.Date.valueOf(ldt.toLocalDate());

,但是显然丢失了时间部分。.我看到还有一个LocalDateTime.toLocalTime(),但是我需要日期和时间在一起。

谢谢

3 个答案:

答案 0 :(得分:4)

这是因为java.sql.Date不包括时间。

您可以改用java.sql.Timestamp类,其中包括日期和时间。

答案 1 :(得分:0)

java.util.Date会保留时间分量(如果您提供的话)。但是首先,您为什么要使用旧的Date而不是新的Java 8 java.time包?无论如何要回答您的问题,我建议检索纪元毫秒,然后从中创建您的Date。所以看起来像这样:

long epoch = ZonedDateTime.of(ldt, ZoneId.systemDefault()).toInstant().toEpochMilli();
Date date = new Date(epoch);

由于Basil Bourque的要求-解释为什么需要ZonedDateTime:为了提取时代-从“ 1.1.1970 00:00:00 + 0000”起的毫秒数,您将需要转换{{ 1}}(不是绝对时间,可能意味着在不同位置的时间不同)到LocalDateTime,它也保存一个位置,因此是绝对时间。因此,您可以从ZonedDateTime中提取纪元。

答案 2 :(得分:0)

tl; dr

显然,您无意中使用了您认为正在使用java.sql.Date的类java.util.Date。但是这个问题没有解决:使用 java.time ,而不是那些糟糕的旧日期时间类。

myPreparedStatement.setObject( … , myLocalDateTime ) ;

…和…

myResultSet.getObject( … , LocalDateTime.class ) 

检查您的进口货

很显然,您无意中使用了java.sql.Date,它假装没有一天的时间。不幸的是,可怕的类设计继承自java.util.Date,它确实有一天的时间。因此sql将其时间设置为00:00:00。并且文档告诉我们忽略它们继承的事实。糟糕的设计,糟糕的名字和周围可怕的阶级。

避免使用旧的日期时间类

由于所有这些原因以及更多原因,这些旧类在几年前被 java.time 类所取代。

JDBC 4.2

从JDBC 4.2开始,我们可以与数据库交换 java.time 类。无需再次触摸java.util.Datejava.sql.Datejava.sql.Timestamp

无区域

LocalDateTime应该存储在类似于SQL标准类型TIMESTAMP WITHOUT TIME ZONE的数据库列中。这些类型有意缺少时区或从UTC偏移的任何概念。因此,这些类型不能代表一个时刻,不能在时间轴上保留特定点。在大多数业务场景中,这些可能不是

myPreparedStatement.setObject( … , myLocalDateTime ) ;

检索:

myLocalDateTime = myResultSet.getObject( … , LocalDateTime.class ) ;

如果它们不能代表片刻,那么这些类型有什么用?在什么情况下使用java.time.LocalDateTime类和TIMESTAMP WITHOUT TIME ZONE列是合适的?这三个:

  • 区域或偏移量未知
    这很糟糕。这是错误的数据。类似于在不知道货币的情况下具有价格/成本。您应该拒绝此类数据,而不是将其存储。
  • 意图是“随处可见” ,例如在每个时区。
    例如,一项公司政策规定“我们所有的工厂都会在12:30休息午餐”意味着德里的工厂要比杜塞尔多夫的工厂早几个小时,底特律的工厂要早几个小时。
  • 打算在未来的某个特定时刻,但我们害怕政界人士重新定义时区
    政府通过surprising frequencylittle warning甚至no warning at all令人惊讶。因此,如果您想在某个日期的下午3点预订约会,并且您的意思是真正的下午3点,而不管政府在此期间可能做出的任何疯狂决定,那么请存储LocalDateTime。要打印报告或显示日历,请动态应用时区(ZoneId)以生成特定时刻(ZonedDateTimeInstant)。此操作必须即时完成,而不是存储值。

带区域

相反,要存储时刻,请使用类似于SQL标准类型TIMESTAMP WITH TIME ZONE的数据库列。对于此类列,在Java中使用Instant类。此类表示UTC中的时刻,分辨率为nanoseconds

myPreparedStatement.setObject( … , myInstant ) ;

检索:

myInstant = myResultSet.getObject( … , Instant.class ) ;

应用时区

如果您确定LocalDateTime是隐式表示特定地区(时区)的人们在墙上时钟中使用的时刻,请应用ZoneId以获得一个ZonedDateTime

continent/region的格式指定proper time zone name,例如America/MontrealAfrica/CasablancaPacific/Auckland。切勿使用3-4个字母的缩写,例如ESTIST,因为它们不是真正的时区,不是标准化的,甚至不是唯一的(!)。

ZoneId z = ZoneId.of( "Pacific/Auckland" ) ;
ZonedDateTime zdt = myLocalDateTime.atZone( z ) ;

然后提取一个Instant对象以调整为UTC

Instant instant = zdt.toInstant(); 

存储在数据库中。

myPreparedStatement.setObject( … , instant ) ;

从数据库检索。

Instant instant = myResultSet.getObject( … , Instant.class ) ;

关于 java.time

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

目前位于Joda-Timemaintenance mode项目建议迁移到java.time类。

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

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

在哪里获取java.time类?

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