XMLGregorianCalendar到java.sql.Timestamp

时间:2012-10-03 16:20:54

标签: java spring timestamp gregorian-calendar

我正在使用webservices,插入记录,返回XMLGregorianCalendar类型的时间戳值。我需要在java.sql.Timestamp值中转换它,所以我使用这样的函数。

public static java.sql.Timestamp getSqlTimeStamp(XMLGregorianCalendar xgc) {
    if (xgc == null) {
        return null;
    } else {
        return new Timestamp(xgc.toGregorianCalendar().getTime().getTime());
    }
}
Timestamp timestamp=getSqlTimeStamp(ExitInXMLGregor.getTimestamp());

我的问题是在服务器中,插入记录时的时间戳值如下所示:2012-10-03T19:23:22.342 + 02:00

但是当我进行类型转换时,我得到的时间戳值如下:2012-10-03T17:23:22.342

服务器(web服务所在的位置)的时间比我的语言环境多2小时,出于某种原因,我在转换后获得了插入区域设置时间。 问题是我真的需要获取服务器时间,因为在数据库中,时间戳值与服务器时间匹配,并且由于时间戳的值不同,我在更新操作中遇到问题。

拜托,我将不胜感激任何帮助。谢谢!

编辑: 我找到了一个解决方案,但并不完全是我需要的。当我将java.sql.Timestamp格式的时间戳转换为XMLGregorian时,我设置服务器的timeZone(setTimeZone(TimeZone.getTimeZone(“GMT + 02:00”)))。这实际上是有效的,但是远离理想的解决方案(可能会发生时区甚至服务器更改)在这一点上知道服务器的时区是非常好的,但我不知道如何...

public static XMLGregorianCalendar getXMLGregorianCalendar(Timestamp timestamp)
        throws BaseException {
    try {
        GregorianCalendar gc = new GregorianCalendar();
        gc.setTimeZone(TimeZone.getTimeZone("GMT+02:00"));
        gc.setTimeInMillis(timestamp.getTime());
        return DatatypeFactory.newInstance().newXMLGregorianCalendar(gc);
    } catch (DatatypeConfigurationException ex) {
        throw new BaseException(ex);
    }
}

2 个答案:

答案 0 :(得分:1)

我怀疑时间戳确实指定了正确的时间,只是没有显示正确的时区。 2012-10-03T17:23:22.342与2012-10-03T19:23:22.342 + 02:00相同,假设前者的(隐藏)时区为+00:00。

答案 1 :(得分:0)

tl; dr

  • 两个字符串都代表相同的时刻,只需将其调整为时区即可,而不会注意offset-from-UTC
  • 通过始终在此类字符串中包含偏移量和区域信息来避免这种混淆。
  • 使用现代的 java.time 类代替麻烦的旧类。 ({Instant,而不是Timestamp

示例代码。

myPreparedStatement.setObject( 
    … , 
    myXMLGregorianCalendar  // If forced to work with a `javax.xml.datatype.XMLGregorianCalendar` object rather than a modern java.time class…
    .toGregorianCalendar()  // …convert to a `java.util.GregorianCalendar`, and then…
    .toZonedDateTime()      // …convert to modern `java.time.ZonedDateTime` class.
    .toInstant()            // Adjust to UTC by extracting an `Instant` object.
)

从JDBC 4.2及更高版本开始从数据库检索。

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

java.time

就像correct accepted Answer by Robert Tupelo-Schneck所说的那样,似乎一切都很好,因为两个字符串都表示相同的时刻,但被调整为具有不同的UTC偏移量的不同时区。问题在于这两个字符串之一缺少其与UTC的偏移量的指标。

这种遗漏是一种不好的做法,因为它会造成这种混乱。除非绝对确定上下文清楚地说明了偏移量/区域,否则请始终包括从UTC偏移量。

在UTC工作

在UTC工作避免了这种混乱。通常,最好在UTC中工作,存储和交换日期时间值。从UTC调整为仅向用户显示或业务逻辑要求的时区。

此外,您正在使用非常麻烦的旧类,这些旧类现在已被 java.time 类所取代。将您的XMLGregorianCalendar转换为java.time.ZonedDateTime

ZonedDateTime zdt = myXMLGregorianCalendar.toGregorianCalendar().toZonedDateTime() ;

通过提取Instant对象来适应UTC。

Instant instant = zdt.toInstant() ;

从JDBC 4.2及更高版本开始,您可以直接与数据库交换 java.time 对象。无需再使用旧版java.sql.Timestamp类。

myPreparedStatement.setObject( … , instant ) ;

检索:

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

如果要使用特定地区的人们使用的挂钟时间查看同一时刻,请从UTC调整到某个特定时区。

ZoneId z = ZoneId.of( "Africa/Tunis" ) ;
ZonedDateTime zdt = instant.atZone( z ) ;

转换

如果必须与一些需要java.sql.Timestamp的旧代码交互,则可以使用java.time.Instant来回转换。调用添加到旧类中的新转换方法。

java.sql.Timestamp ts = java.sql.Timestamp.from( instant ) ;

往另一个方向。

Instant instant = ts.toInstant() ;

另请参见my Answer,类似的问题。


关于 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