diff --git a/src/main/java/microsoft/sql/DateTimeOffset.java b/src/main/java/microsoft/sql/DateTimeOffset.java index e2fcc8409..f57d74a25 100644 --- a/src/main/java/microsoft/sql/DateTimeOffset.java +++ b/src/main/java/microsoft/sql/DateTimeOffset.java @@ -72,6 +72,22 @@ private DateTimeOffset(java.sql.Timestamp timestamp, int minutesOffset) { assert 0 == this.utcMillis % 1000L : "utcMillis: " + this.utcMillis; } + /** + * Constructs a DateTimeOffset from an existing java.time.OffsetDateTime + * + * @param offsetDateTime + * A java.time.OffsetDateTime value + * @apiNote DateTimeOffset represents values to 100 nanosecond precision. If the java.time.OffsetDateTime instance + * represents a value that is more precise, the value is rounded to the nearest multiple of 100 nanoseconds. Values + * within 50 nanoseconds of the next second are rounded up to the next second. + */ + private DateTimeOffset(java.time.OffsetDateTime offsetDateTime) { + int hundredNanos = ((offsetDateTime.getNano() + 50) / 100); + this.utcMillis = (offsetDateTime.toEpochSecond() * 1000) + (hundredNanos / HUNDRED_NANOS_PER_SECOND * 1000); + this.nanos = 100 * (hundredNanos % HUNDRED_NANOS_PER_SECOND); + this.minutesOffset = offsetDateTime.getOffset().getTotalSeconds() / 60; + } + /** * Converts a java.sql.Timestamp value with an integer offset to the equivalent DateTimeOffset value * @@ -105,6 +121,20 @@ public static DateTimeOffset valueOf(java.sql.Timestamp timestamp, Calendar cale (calendar.get(Calendar.ZONE_OFFSET) + calendar.get(Calendar.DST_OFFSET)) / (60 * 1000)); } + /** + * Directly converts a {@link java.time.OffsetDateTime} value to an equivalent {@link DateTimeOffset} value + * + * @param offsetDateTime + * A java.time.OffsetDateTime value + * @return The DateTimeOffset value of the input java.time.OffsetDateTime + * @apiNote DateTimeOffset represents values to 100 nanosecond precision. If the java.time.OffsetDateTime instance + * represents a value that is more precise, the value is rounded to the nearest multiple of 100 nanoseconds. Values + * within 50 nanoseconds of the next second are rounded up to the next second. + */ + public static DateTimeOffset valueOf(java.time.OffsetDateTime offsetDateTime) { + return new DateTimeOffset(offsetDateTime); + } + /** formatted value */ private String formattedValue = null; diff --git a/src/test/java/com/microsoft/sqlserver/jdbc/datatypes/DataTypesTest.java b/src/test/java/com/microsoft/sqlserver/jdbc/datatypes/DataTypesTest.java index 350f7cfc3..445d23dd0 100644 --- a/src/test/java/com/microsoft/sqlserver/jdbc/datatypes/DataTypesTest.java +++ b/src/test/java/com/microsoft/sqlserver/jdbc/datatypes/DataTypesTest.java @@ -1935,6 +1935,17 @@ public void testGetLocalDateTimeUnstorable() throws Exception { } } + @Test + public void testDateTimeOffsetValueOfOffsetDateTime() throws Exception { + OffsetDateTime expected = OffsetDateTime.now().withSecond(58).withNano(0); + OffsetDateTime roundUp = expected.withSecond(57).withNano(999999950); + OffsetDateTime roundDown = expected.withSecond(58).withNano(49); + + assertEquals(expected, DateTimeOffset.valueOf(expected).getOffsetDateTime()); + assertEquals(expected, DateTimeOffset.valueOf(roundUp).getOffsetDateTime()); + assertEquals(expected, DateTimeOffset.valueOf(roundDown).getOffsetDateTime()); + } + static LocalDateTime getUnstorableValue() throws Exception { ZoneId systemTimezone = ZoneId.systemDefault(); Instant now = Instant.now();