将joda.time.DateTime转换为java.sql.Date并保留时区

Jus*_*les 5 java date jdbc jodatime

我有以下场景:

  • 返回Calendar对象的Swing控件
  • DateTime我用来做重日期/时间操作的中间对象(joda)
  • OraclePreparedStatement仅接受java.sql.Date对象的数据库连接()

我的问题是CalendarDateTime对象正在以GMT(我想要)正确显示日期,但是当我转换java.sql.Date为发送到数据库时,日期将转换为本地时区.

例如:

  • Calendar并且DateTime是2012-08-13T23:59:59.000Z(正确GMT)
  • 结果java.sql.Date是2012-08-14(当地UTC + 2日期不正确)

下面是我用来进行转换的代码.

DateTime dateGmt = new DateTime(calendarGmt.getTimeInMillis(), DateTimeZone.UTC);
java.sql.Date sqlDate = new java.sql.Date(dateGmt.getMillis());
Run Code Online (Sandbox Code Playgroud)

我不知道如何java.sql.Date在保留正确时区的同时创建对象.我完全有可能做错误的转换.

Bas*_*que 16

浪费时间

一个问题可能是java.sql.Date应该是......

通过在与实例关联的特定时区中将小时,分钟,秒和毫秒设置为零来"标准化".

......根据文件.这意味着,日期时间的时间部分将从java.util.Date或Joda-Time DateTime对象中清除.

没有时区

正如Gilbert Le Blanc指出的正确答案,java.util.Date和java.sql.Date都没有内部时区的概念.它们存储自Unix 纪元以来的毫秒数.

这些类带来了一个讨厌的技巧:他们的toString方法将JVM的默认时区应用于字符串的渲染.很混乱.该Date对象没有时区,但当显示为字符串时,您会看到一个时区.

如果您的java.util.Date对象包含自纪元(1970年开始)以来的1344902399000L毫秒数,则表示2012-08-13T23:59:59.000Z为UTC/GMT.但是如果你的JVM认为自己在法国夏令时(DST)生效,你会看到提前2小时的UTC/GMT:2012-08-14T01:59:59.000+02:00在那个类中描述的糟糕的字符串格式.同一时刻在不同的时区有不同的日期意义(13对14),墙上的时钟已经过了午夜.

Joda-救援时间

乔达时间 2.4库可以帮助这里.将java.sql.Date或java.util.Date对象与UTC时区对象一起传递给DateTime构造函数,以获得您正在苦苦挣扎的值的清晰图片.

java.util.Date date = new java.util.Date( 1390276603054L );
DateTime dateTimeUtc = new DateTime( date, DateTimeZone.UTC );
System.out.println( "dateTimeUtc: " + dateTimeUtc );
Run Code Online (Sandbox Code Playgroud)

跑的时候......

2014-01-21T03:56:43.054Z
Run Code Online (Sandbox Code Playgroud)

将另一个方向从Joda-Time转换为java.util.Date ...

java.util.Date date = myDateTime.toDate();
Run Code Online (Sandbox Code Playgroud)

将另一个方向从Joda-Time转换为java.sql.Date ...

java.sql.Date date = new java.sql.Date( myDateTime.getMillis() );
Run Code Online (Sandbox Code Playgroud)

更新 - java.time

Joda-Time项目现在处于维护模式,团队建议迁移到java.time类.

相当于java.util.DateInstant.该Instant级表示时间轴上的时刻UTC,分辨率为纳秒(最多9个(9)小数的位数).

Instant instant = Instant.ofEpochMilli( 1390276603054L );
Run Code Online (Sandbox Code Playgroud)

应用时区,ZoneId以产生ZonedDateTime类似于a java.util.Calendar和Joda-Time的时区DateTime.

ZoneId z = ZoneId.of( "Europe/Kaliningrad" );
ZonedDateTime zdt = instant.atZone( z );
Run Code Online (Sandbox Code Playgroud)

现在提取一个仅限日期的值,即日期部分ZonedDateTime,作为LocalDate.该LocalDate级表示没有时间一天和不同时区的日期,唯一的价值.那么LocalDate是什么java.sql.Date假装是:日期,唯一的价值.

LocalDate localDate = zdt.toLocalDate() ;
Run Code Online (Sandbox Code Playgroud)

在JDBC 4.2及更高版本中,您可以通过PreparedStatement::setObject和直接使用兼容的驱动程序使用java.time类型ResultSet::getObject.

myPreparedStatement.setObject( … , localDate );
Run Code Online (Sandbox Code Playgroud)

…和…

LocalDate ld = myResultSet.getObject( … , LocalDate.class );
Run Code Online (Sandbox Code Playgroud)

对于较旧的不兼容驱动程序,通过使用添加到旧类的新方法简单地转换java.sql.Date为/从a 的对象LocalDate:toLocalDatevalueOf( LocalDate ).


Gil*_*anc 7

a的内部表示java.sql.Date是自1970年1月1日00:00:00.000 GMT以来经过的毫秒数.

你确定你没有看到toString问题吗?该方法toGMTString()虽然已经折旧,但仍然存在.