Question

I'm working with webservices, inserting records, that return a timestamp value in XMLGregorianCalendar type. I need to transform it in a java.sql.Timestamp value, so I use a function like this.

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());

My problem is that in the server, the timestamp value when I insert a record, looks like this: 2012-10-03T19:23:22.342+02:00

But when I make my type conversion, I obtain the timestamp value like this: 2012-10-03T17:23:22.342

The time in the server (where the webservice is located) is 2h more than my locale, and for some reason, I obtain my insert locale time, after transform it. The problem is that I really need to obtain the server time, cause in the DB, the timestamp value matches with the server one, and I'm having problems in the update operation, due to the different values of timestamp.

Please, I would appreciate any kind of help. thanks!

Edit: I kind of find a solution, but is not exactly what I need. When I convert my timestamp in java.sql.Timestamp format into XMLGregorian I setting the timeZone of the server (setTimeZone(TimeZone.getTimeZone("GMT+02:00"))). This actually works, but is far away from the ideal solution (It could happen that the timezone or even the server change) It would be great to know in this point the timeZone of the server dinamically, but I don't know how...

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);
    }
}
Was it helpful?

Solution

I suspect the timestamp does specify the correct time, just doesn't display with the right time zone. 2012-10-03T17:23:22.342 is the same as 2012-10-03T19:23:22.342+02:00, assuming the (hidden) time zone of the former is +00:00.

OTHER TIPS

tl;dr

  • Both strings represent the same moment, simply adjusted to a time zone while failing to note the offset-from-UTC.
  • Avoid such confusion by always including the offset and zone info in such strings.
  • Use modern java.time classes that supplant the troublesome legacy classes. (Instant, not Timestamp)

Example code.

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.
)

Retrieving from a database, as of JDBC 4.2 and later.

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

java.time

As the correct accepted Answer by Robert Tupelo-Schneck says, it seems all is well in that both strings represent the same moment but adjusted into a different time zone with a different offset-from-UTC. The problem is that one of those two strings lacks an indicator of its offset-from-UTC.

Such an omission is a bad practice as it creates this confusion. Always include the offset-from-UTC unless absolutely certain the context makes the offset/zone clear.

Work in UTC

Working in UTC avoids this kind of confusion. Generally best to work, store, and exchange date-time values in UTC. Adjust from UTC to a time zone only for presentation to the user or where required by business logic.

Also, you are using terribly troublesome old classes that are now supplanted by the java.time classes. Convert your XMLGregorianCalendar to java.time.ZonedDateTime.

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

Adjust to UTC by extracting an Instant object.

Instant instant = zdt.toInstant() ;

As of JDBC 4.2 and later, you can directly exchange java.time objects with the database. No need to ever use the legacy java.sql.Timestamp class again.

myPreparedStatement.setObject( … , instant ) ;

Retrieval:

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

Adjust from UTC to some particular time zone if you want to view the same moment using the wall-clock time used by the people of a particular region.

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

Convert

If you must interface with some old code requiring a java.sql.Timestamp, you can convert back-and-forth with java.time.Instant. Call new conversion methods added to the old classes.

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

Going the other direction.

Instant instant = ts.toInstant() ;

See also my Answer to a similar Question.


About java.time

The java.time framework is built into Java 8 and later. These classes supplant the troublesome old legacy date-time classes such as java.util.Date, Calendar, & SimpleDateFormat.

The Joda-Time project, now in maintenance mode, advises migration to the java.time classes.

To learn more, see the Oracle Tutorial. And search Stack Overflow for many examples and explanations. Specification is JSR 310.

You may exchange java.time objects directly with your database. Use a JDBC driver compliant with JDBC 4.2 or later. No need for strings, no need for java.sql.* classes.

Where to obtain the java.time classes?

The ThreeTen-Extra project extends java.time with additional classes. This project is a proving ground for possible future additions to java.time. You may find some useful classes here such as Interval, YearWeek, YearQuarter, and more.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top