Skip to content

Commit

Permalink
Fix OffsetDateTime conversion for pre-Gregorian dates (#2568)
Browse files Browse the repository at this point in the history
* Fix OffsetDateTime conversion for pre-Gregorian dates

* Formatting changes

* Removed unused import
  • Loading branch information
machavan authored Dec 24, 2024
1 parent 4497e05 commit 74a5cb8
Show file tree
Hide file tree
Showing 2 changed files with 55 additions and 6 deletions.
33 changes: 27 additions & 6 deletions src/main/java/microsoft/sql/DateTimeOffset.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@

package microsoft.sql;

import java.time.OffsetDateTime;
import java.time.ZoneOffset;
import java.util.Calendar;
import java.util.Locale;
import java.util.TimeZone;
Expand Down Expand Up @@ -190,7 +192,6 @@ public String toString() {
.substring(2), // -> "123456"
formattedOffset);
}

return result;
}

Expand Down Expand Up @@ -257,12 +258,32 @@ public java.sql.Timestamp getTimestamp() {
* @return OffsetDateTime equivalent to this DateTimeOffset object.
*/
public java.time.OffsetDateTime getOffsetDateTime() {
java.time.ZoneOffset zoneOffset = java.time.ZoneOffset.ofTotalSeconds(60 * minutesOffset);
java.time.LocalDateTime localDateTime = java.time.LocalDateTime.ofEpochSecond(utcMillis / 1000, nanos,
zoneOffset);
return java.time.OffsetDateTime.of(localDateTime, zoneOffset);
// Format the offset as +hh:mm or -hh:mm. Zero offset is formatted as +00:00.
String formattedOffset = (minutesOffset < 0) ?
String.format(Locale.US, "-%1$02d:%2$02d", -minutesOffset / 60, -minutesOffset % 60) :
String.format(Locale.US, "+%1$02d:%2$02d", minutesOffset / 60, minutesOffset % 60);

// Create a Calendar instance with the time zone set to GMT plus the formatted offset
Calendar calendar = Calendar.getInstance(TimeZone.getTimeZone("GMT" + formattedOffset), Locale.US);
// Initialize the calendar with the UTC milliseconds value
calendar.setTimeInMillis(utcMillis);

// Extract the date and time components from the calendar
int year = calendar.get(Calendar.YEAR);
int month = calendar.get(Calendar.MONTH) + 1; // Calendar.MONTH is zero-based
int day = calendar.get(Calendar.DAY_OF_MONTH);
int hour = calendar.get(Calendar.HOUR_OF_DAY);
int minute = calendar.get(Calendar.MINUTE);
int second = calendar.get(Calendar.SECOND);

// Create the ZoneOffset from the minutesOffset
ZoneOffset offset = ZoneOffset.ofTotalSeconds(minutesOffset * 60);

// Create and return the OffsetDateTime
return OffsetDateTime.of(year, month, day, hour, minute, second, nanos, offset);
}



/**
* Returns this DateTimeOffset object's offset value.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1945,6 +1945,34 @@ public void testDateTimeOffsetValueOfOffsetDateTime() throws Exception {
assertEquals(expected, DateTimeOffset.valueOf(roundUp).getOffsetDateTime());
assertEquals(expected, DateTimeOffset.valueOf(roundDown).getOffsetDateTime());
}

@Test
public void testPreGregorianDateTime() throws Exception {
try (Connection conn = getConnection();
Statement stmt = conn.createStatement(ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_UPDATABLE);) {

conn.setAutoCommit(false);
TestUtils.dropTableIfExists(escapedTableName, stmt);

stmt.executeUpdate("CREATE TABLE " + escapedTableName + " (dob datetimeoffset(7) null)");
stmt.executeUpdate("INSERT INTO " + escapedTableName + " VALUES ('1500-12-16 00:00:00.0000000+08:00')");
stmt.executeUpdate("INSERT INTO " + escapedTableName + " VALUES ('1400-09-27 09:30:00.0000000+08:00')");
stmt.executeUpdate("INSERT INTO " + escapedTableName + " VALUES ('2024-12-16 23:40:00.0000000+08:00')");

try (ResultSet rs = stmt.executeQuery("select dob from " + escapedTableName + " order by dob")) {
while (rs.next()) {
String strDateTimeOffset = rs.getString(1).substring(0, 10);
DateTimeOffset objDateTimeOffset = (DateTimeOffset) rs.getObject(1);
OffsetDateTime objOffsetDateTime = objDateTimeOffset.getOffsetDateTime();

String strOffsetDateTime = objOffsetDateTime.toString().substring(0, 10);
assertEquals(strDateTimeOffset, strOffsetDateTime, "Mismatch found in DateTimeOffset : "
+ objDateTimeOffset + " and OffsetDateTime : " + objOffsetDateTime);
}
}
TestUtils.dropTableIfExists(escapedTableName, stmt);
}
}

static LocalDateTime getUnstorableValue() throws Exception {
ZoneId systemTimezone = ZoneId.systemDefault();
Expand Down

0 comments on commit 74a5cb8

Please sign in to comment.