1111import java .sql .Types ;
1212import java .time .Instant ;
1313import java .time .LocalDate ;
14+ import java .time .LocalTime ;
1415import java .time .OffsetDateTime ;
1516import java .time .OffsetTime ;
1617import java .time .ZoneOffset ;
17- import java .time .ZonedDateTime ;
1818import java .time .format .DateTimeFormatter ;
1919import java .util .Calendar ;
2020import java .util .Date ;
@@ -76,31 +76,46 @@ public <X> X unwrap(OffsetTime offsetTime, Class<X> type, WrapperOptions options
7676 return null ;
7777 }
7878
79+ // for java.time types, we assume that the JDBC timezone, if any, is ignored
80+ // (since PS.setObject() doesn't support passing a timezone)
81+
7982 if ( OffsetTime .class .isAssignableFrom ( type ) ) {
8083 return (X ) offsetTime ;
8184 }
8285
86+ if ( LocalTime .class .isAssignableFrom ( type ) ) {
87+ return (X ) offsetTime .withOffsetSameInstant ( getCurrentSystemOffset () ).toLocalTime ();
88+ }
89+
90+ // for legacy types, we assume that the JDBC timezone is passed to JDBC
91+ // (since PS.setTime() and friends do accept a timezone passed as a Calendar)
92+
93+ final OffsetTime jdbcOffsetTime = offsetTime .withOffsetSameInstant ( getCurrentJdbcOffset (options ) );
94+
8395 if ( Time .class .isAssignableFrom ( type ) ) {
84- return (X ) Time .valueOf ( offsetTime .toLocalTime () );
96+ return (X ) Time .valueOf ( jdbcOffsetTime .toLocalTime () );
8597 }
8698
87- final ZonedDateTime zonedDateTime = offsetTime .atDate ( LocalDate .of ( 1970 , 1 , 1 ) ). toZonedDateTime ( );
99+ final OffsetDateTime jdbcOffsetDateTime = jdbcOffsetTime .atDate ( LocalDate .EPOCH );
88100
89101 if ( Timestamp .class .isAssignableFrom ( type ) ) {
90102 /*
91103 * Workaround for HHH-13266 (JDK-8061577).
92- * Ideally we'd want to use Timestamp.from( offsetDateTime.toInstant() ), but this won't always work.
93- * Timestamp.from() assumes the number of milliseconds since the epoch
94- * means the same thing in Timestamp and Instant, but it doesn't, in particular before 1900.
104+ * Ideally we'd want to use Timestamp.from( jdbcOffsetDateTime.toInstant() ),
105+ * but this won't always work since Timestamp.from() assumes the number of
106+ * milliseconds since the epoch means the same thing in Timestamp and Instant,
107+ * but it doesn't, in particular before 1900.
95108 */
96- return (X ) Timestamp .valueOf ( zonedDateTime .toLocalDateTime () );
109+ return (X ) Timestamp .valueOf ( jdbcOffsetDateTime .toLocalDateTime () );
97110 }
98111
99112 if ( Calendar .class .isAssignableFrom ( type ) ) {
100- return (X ) GregorianCalendar .from ( zonedDateTime );
113+ return (X ) GregorianCalendar .from ( jdbcOffsetDateTime . toZonedDateTime () );
101114 }
102115
103- final Instant instant = zonedDateTime .toInstant ();
116+ // for instants, we assume that the JDBC timezone, if any, is ignored
117+
118+ final Instant instant = offsetTime .atDate ( LocalDate .EPOCH ).toInstant ();
104119
105120 if ( Long .class .isAssignableFrom ( type ) ) {
106121 return (X ) Long .valueOf ( instant .toEpochMilli () );
@@ -119,10 +134,17 @@ public <X> OffsetTime wrap(X value, WrapperOptions options) {
119134 return null ;
120135 }
121136
137+ // for java.time types, we assume that the JDBC timezone, if any, is ignored
138+ // (since PS.setObject() doesn't support passing a timezone)
139+
122140 if (value instanceof OffsetTime ) {
123141 return (OffsetTime ) value ;
124142 }
125143
144+ if (value instanceof LocalTime ) {
145+ return ((LocalTime ) value ).atOffset ( getCurrentSystemOffset () );
146+ }
147+
126148 /*
127149 * Also, in order to fix HHH-13357, and to be consistent with the conversion to Time (see above),
128150 * we set the offset to the current offset of the JVM (OffsetDateTime.now().getOffset()).
@@ -137,30 +159,39 @@ public <X> OffsetTime wrap(X value, WrapperOptions options) {
137159 * Of course none of this would be a problem if we just stored the offset in the database,
138160 * but I guess there are historical reasons that explain why we don't.
139161 */
140- ZoneOffset offset = OffsetDateTime .now ().getOffset ();
162+
163+ // for legacy types, we assume that the JDBC timezone is passed to JDBC
164+ // (since PS.setTime() and friends do accept a timezone passed as a Calendar)
141165
142166 if (value instanceof Time ) {
143- return ( (Time ) value ).toLocalTime ().atOffset ( offset );
167+ final Time time = (Time ) value ;
168+ return time .toLocalTime ().atOffset ( getCurrentJdbcOffset (options ) )
169+ .withOffsetSameInstant ( getCurrentSystemOffset () );
144170 }
145171
146172 if (value instanceof Timestamp ) {
147173 final Timestamp ts = (Timestamp ) value ;
148174 /*
149175 * Workaround for HHH-13266 (JDK-8061577).
150- * Ideally we'd want to use OffsetDateTime.ofInstant( ts.toInstant(), ... ), but this won't always work.
151- * ts.toInstant() assumes the number of milliseconds since the epoch
152- * means the same thing in Timestamp and Instant, but it doesn't, in particular before 1900.
176+ * Ideally we'd want to use OffsetDateTime.ofInstant( ts.toInstant(), ... ),
177+ * but this won't always work since ts.toInstant() assumes the number of
178+ * milliseconds since the epoch means the same thing in Timestamp and Instant,
179+ * but it doesn't, in particular before 1900.
153180 */
154- return ts .toLocalDateTime ().toLocalTime ().atOffset ( offset );
181+ return ts .toLocalDateTime ().toLocalTime ().atOffset ( getCurrentJdbcOffset (options ) )
182+ .withOffsetSameInstant ( getCurrentSystemOffset () );
155183 }
156184
157185 if (value instanceof Date ) {
158186 final Date date = (Date ) value ;
159- return OffsetTime .ofInstant ( date .toInstant (), offset );
187+ return OffsetTime .ofInstant ( date .toInstant (), getCurrentSystemOffset () );
160188 }
161189
190+ // for instants, we assume that the JDBC timezone, if any, is ignored
191+
162192 if (value instanceof Long ) {
163- return OffsetTime .ofInstant ( Instant .ofEpochMilli ( (Long ) value ), offset );
193+ final long millis = (Long ) value ;
194+ return OffsetTime .ofInstant ( Instant .ofEpochMilli (millis ), getCurrentSystemOffset () );
164195 }
165196
166197 if (value instanceof Calendar ) {
@@ -171,6 +202,19 @@ public <X> OffsetTime wrap(X value, WrapperOptions options) {
171202 throw unknownWrap ( value .getClass () );
172203 }
173204
205+ private static ZoneOffset getCurrentJdbcOffset (WrapperOptions options ) {
206+ if ( options .getJdbcTimeZone () != null ) {
207+ return OffsetDateTime .now ().atZoneSameInstant ( options .getJdbcTimeZone ().toZoneId () ).getOffset ();
208+ }
209+ else {
210+ return getCurrentSystemOffset ();
211+ }
212+ }
213+
214+ private static ZoneOffset getCurrentSystemOffset () {
215+ return OffsetDateTime .now ().getOffset ();
216+ }
217+
174218 @ Override
175219 public int getDefaultSqlPrecision (Dialect dialect , JdbcType jdbcType ) {
176220 return 0 ;
0 commit comments