Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

using the datetimeoffset datatype with jTDS

jTDS currently doesn't support the datetimeoffset datatype introduced in SQL Server 2008.

Can anybody suggest if there is a way to use the datetimeoffset type with jTDS?

like image 610
Amiya Avatar asked Apr 04 '16 14:04

Amiya


People also ask

What does DateTimeOffset mean in SQL?

The DATETIMEOFFSET allows you to manipulate any single point in time, which is a datetime value, along with an offset that specifies how much that datetime differs from UTC.

What is the difference between DateTime and DateTimeOffset?

With its Kind property, DateTime is able to reflect only Coordinated Universal Time (UTC) and the system's local time zone. DateTimeOffset reflects a time's offset from UTC, but it does not reflect the actual time zone to which that offset belongs.

How do I get UTC offset in SQL Server?

Extracting the Time Zone Offset You can use the DATEPART() function to return the time zone offset. This function returns an integer that represents the time zone offset in minutes. You can also use the FORMAT() function to return the time zone offset as a string.

Does DateTime have timezone SQL?

A time zone offset specifies the zone offset from UTC for a time or datetime value. The time zone offset can be represented as [+|-] hh:mm: hh is two digits that range from 00 to 14 and represent the number of hours in the time zone offset.


1 Answers

As mentioned in the "Backward Compatibility for Down-level Clients" section of the datetimeoffset documentation, we can work with string representations of datetimeoffset values. In fact, if we retrieve a datetimeoffset value with jTDS 1.3.1 we get a java.lang.String value of the form

YYYY-MM-DD hh:mm:ss[.nnnnnnn] {+|-}hh:mm

Such a value can be parsed like so:

// rs is our ResultSet object
String valueRetrieved = rs.getString(1);  // e.g., "2016-12-08 12:34:56.7850000 -07:00"
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSSSSSS ZZZZZ");
ZonedDateTime zdt = ZonedDateTime.parse(valueRetrieved, dtf);

As for writing a datetimeoffset value to SQL Server, jTDS is unable to properly handle an update using .setTimestamp, e.g., on my machine ...

java.sql.Timestamp ts = java.sql.Timestamp.valueOf("2016-12-08 12:34:56.785");  // local
String tsString = formatTimestampForDateTimeOffset(ts);  // (see below)
System.out.printf("             java.sql.TimeStamp value: %s (%d ms since epoch)%n", tsString, ts.getTime());

System.out.println();
System.out.println("Saving via setTimestamp ...");
String sqlUpdate = "UPDATE dtoTable SET dtoCol = ? WHERE id=1";
try (PreparedStatement s = conn.prepareStatement(sqlUpdate)) {
    s.setTimestamp(1, ts);  // pass the Timestamp itself
    s.executeUpdate();
}
String valueRetrieved;
try (
        Statement s = conn.createStatement();
        ResultSet rs = s.executeQuery("SELECT dtoCol FROM dtoTable WHERE id=1")) {
    rs.next();
    valueRetrieved = rs.getString(1);
    System.out.printf("    jTDS saved the TimeStamp value as: %s%n", valueRetrieved);
}

... produces ...

         java.sql.TimeStamp value: 2016-12-08 12:34:56.785 -07:00 (1481225696785 ms since epoch)

Saving via setTimestamp ...
jTDS saved the TimeStamp value as: 2016-12-08 12:34:56.7870000 +00:00

... which not only incorrectly sets the timezone offset to +00:00 (without changing the date/time value itself), it also adds a couple of milliseconds just for fun.

However, if we convert the Timestamp value to a properly-formatted String, e.g., ...

public static String formatTimestampForDateTimeOffset(java.sql.Timestamp ts) {
    SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS ZZZZZ");
    String s = sdf.format(new Date(ts.getTime()));
    // T-SQL *requires* the colon in the timezone offset: -07:00, not -0700
    int colonPosition = s.length() - 2;
    return s.substring(0, colonPosition) + ":" + s.substring(colonPosition);
}

... and use .setString instead of .setTimestamp, then the datetimeoffset value is saved correctly:

Saving via setString ...
jTDS saved the formatted String as: 2016-12-08 12:34:56.7850000 -07:00
           parsed to ZonedDateTime: 2016-12-08T12:34:56.785-07:00
              converted to Instant: 2016-12-08T19:34:56.785Z
       converted to java.util.Date: Thu Dec 08 12:34:56 MST 2016
like image 66
Gord Thompson Avatar answered Oct 05 '22 06:10

Gord Thompson