Skip to content

Commit b31ac66

Browse files
committed
Catch HOUR_OF_DAY error
If the time stored in the missing daylight saving hour, MySQL JDBC driver starting from version 8.0.23 will raise this error (https://dev.mysql.com/doc/relnotes/connector-j/en/news-8-0-23.html) If the date time value stored in the column actually is UTC time, then will return string representation of the value, not the time converted to the local time zone.
1 parent 6b3983b commit b31ac66

File tree

2 files changed

+68
-0
lines changed

2 files changed

+68
-0
lines changed

src/java/arjdbc/mysql/MySQLRubyJdbcConnection.java

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -217,6 +217,39 @@ protected IRubyObject timeToRuby(final ThreadContext context,
217217
return DateTimeUtils.newDummyTime(context, value, getDefaultTimeZone(context));
218218
}
219219

220+
@Override
221+
protected IRubyObject timestampToRuby(final ThreadContext context,
222+
final Ruby runtime, final ResultSet resultSet, final int column)
223+
throws SQLException {
224+
225+
final Timestamp value;
226+
try {
227+
value = resultSet.getTimestamp(column);
228+
}
229+
catch (SQLException e) {
230+
if (e.getMessage().contains("HOUR_OF_DAY")) {
231+
return stringToRuby(context, runtime, resultSet, column);
232+
}
233+
else {
234+
throw e;
235+
}
236+
}
237+
if ( value == null ) {
238+
return resultSet.wasNull() ? context.nil : RubyString.newEmptyString(runtime);
239+
}
240+
241+
if ( rawDateTime != null && rawDateTime) {
242+
return RubyString.newString(runtime, DateTimeUtils.timestampToString(value));
243+
}
244+
245+
// NOTE: with 'raw' String AR's Type::DateTime does put the time in proper time-zone
246+
// while when returning a Time object it just adjusts usec (apply_seconds_precision)
247+
// yet for custom SELECTs to work (SELECT created_at ... ) and for compatibility we
248+
// should be returning Time (by default) - AR does this by adjusting mysql2/pg returns
249+
250+
return DateTimeUtils.newTime(context, value, getDefaultTimeZone(context));
251+
}
252+
220253
@Override
221254
protected IRubyObject streamToRuby(final ThreadContext context,
222255
final Ruby runtime, final ResultSet resultSet, final int column)

test/simple.rb

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -321,7 +321,42 @@ def test_time_with_default_timezone_local
321321
end
322322
end
323323
end
324+
end
325+
326+
def test_time_in_dst_change_hour_utc
327+
with_system_tz 'Europe/Prague' do
328+
Time.use_zone 'Europe/Prague' do
329+
with_timezone_config default: :utc do
330+
id = DbType.connection.insert(
331+
"INSERT INTO db_types (sample_datetime)
332+
values ('2024-03-31 03:30:00')"
333+
)
334+
saved_time = DbType.find(id).sample_datetime
335+
336+
assert_equal Time.utc(2024, 3, 31, 3, 30), saved_time
337+
assert_equal 'UTC', saved_time.zone
338+
end
339+
end
340+
end
341+
end
342+
343+
def test_time_in_dst_change_hour_local
344+
skip "with_system_tz not working in tomcat" if ActiveRecord::Base.connection.raw_connection.jndi?
345+
346+
with_system_tz 'Europe/Prague' do
347+
Time.use_zone 'Europe/Prague' do
348+
with_timezone_config default: :local do
349+
id = DbType.connection.insert(
350+
"INSERT INTO db_types (sample_datetime)
351+
values ('2024-03-31 02:30:00')"
352+
)
353+
saved_time = DbType.find(id).sample_datetime
324354

355+
assert_equal Time.local(2024, 3, 31, 1, 30), saved_time
356+
assert_not_equal 'UTC', saved_time.zone
357+
end
358+
end
359+
end
325360
end
326361

327362
#

0 commit comments

Comments
 (0)