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?
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.
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.
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.
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.
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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With