7

我有以下情况:

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

我的问题是CalendarandDateTime对象在 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());

我不知道如何java.sql.Date在保留正确时区的同时创建对象。我也完全有可能进行了不正确的转换。

4

3 回答 3

17

浪费时间

一个问题可能是 java.sql.Date 应该是……</p>

通过在与实例关联的特定时区将小时、分钟、秒和毫秒设置为零来实现“标准化”。

…根据文档。这意味着,日期时间的时间部分正在从您的 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) 的法国,您将看到比 UTC/GMT 提前 2 小时:2012-08-14T01:59:59.000+02:00在该类的糟糕字符串格式中描述。同一时刻在不同时区具有不同的月份含义(13 对 14),墙上的时钟已经过了午夜。

乔达救援时间

Joda-Time 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 );

运行时……</p>

2014-01-21T03:56:43.054Z

将另一个方向从 Joda-Time 转换为 java.util.Date…</p>

java.util.Date date = myDateTime.toDate();

将另一个方向从 Joda-Time 转换为 java.sql.Date…</p>

java.sql.Date date = new java.sql.Date( myDateTime.getMillis() );

更新——java.time

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

的等价物java.util.DateInstant。该类表示UTCInstant时间线上的时刻,分辨率为纳秒(最多九 (9) 位小数)。

Instant instant = Instant.ofEpochMilli( 1390276603054L );

应用时区 ,ZoneId来生成ZonedDateTime类似于 ajava.util.Calendar和 Joda-Time的 a DateTime

ZoneId z = ZoneId.of( "Europe/Kaliningrad" );
ZonedDateTime zdt = instant.atZone( z );

现在提取一个仅限日期的值,即 的日期部分ZonedDateTime,作为LocalDate. 该类LocalDate表示没有时间和时区的仅日期值。假装的也是如此:仅日期LocalDate值。java.sql.Date

LocalDate localDate = zdt.toLocalDate() ;

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

myPreparedStatement.setObject( … , localDate );

……和……</p>

LocalDate ld = myResultSet.getObject( … , LocalDate.class );

对于较旧的不兼容驱动程序,通过使用添加到旧java.sql.DateLocalDate的新方法toLocalDatevalueOf( LocalDate ).

于 2014-01-21T05:44:42.823 回答
7

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

你确定你不是在看toString问题吗?该方法toGMTString()虽然贬值,但仍然存在。

于 2012-08-13T16:34:19.710 回答
1

我想您可能需要在配置文件中添加 TIMEZONE=GMT

在 web 应用程序中,这是在 web.xml 中定义的

<context-param> <param-name>javax.faces.DATETIMECONVERTER_DEFAULT_TIMEZONE_IS_SYSTEM_TIMEZONE</p‌​aram-name> <param-value>true</param-value> </context-param>

问候

于 2012-08-13T16:20:04.850 回答