diff --git a/src/java/arjdbc/mysql/MySQLRubyJdbcConnection.java b/src/java/arjdbc/mysql/MySQLRubyJdbcConnection.java index 140f722ee..4b2f4fa0d 100644 --- a/src/java/arjdbc/mysql/MySQLRubyJdbcConnection.java +++ b/src/java/arjdbc/mysql/MySQLRubyJdbcConnection.java @@ -217,6 +217,39 @@ protected IRubyObject timeToRuby(final ThreadContext context, return DateTimeUtils.newDummyTime(context, value, getDefaultTimeZone(context)); } + @Override + protected IRubyObject timestampToRuby(final ThreadContext context, + final Ruby runtime, final ResultSet resultSet, final int column) + throws SQLException { + + final Timestamp value; + try { + value = resultSet.getTimestamp(column); + } + catch (SQLException e) { + if (e.getMessage().contains("HOUR_OF_DAY")) { + return stringToRuby(context, runtime, resultSet, column); + } + else { + throw e; + } + } + if ( value == null ) { + return resultSet.wasNull() ? context.nil : RubyString.newEmptyString(runtime); + } + + if ( rawDateTime != null && rawDateTime) { + return RubyString.newString(runtime, DateTimeUtils.timestampToString(value)); + } + + // NOTE: with 'raw' String AR's Type::DateTime does put the time in proper time-zone + // while when returning a Time object it just adjusts usec (apply_seconds_precision) + // yet for custom SELECTs to work (SELECT created_at ... ) and for compatibility we + // should be returning Time (by default) - AR does this by adjusting mysql2/pg returns + + return DateTimeUtils.newTime(context, value, getDefaultTimeZone(context)); + } + @Override protected IRubyObject streamToRuby(final ThreadContext context, final Ruby runtime, final ResultSet resultSet, final int column) diff --git a/test/db/mysql/simple_test.rb b/test/db/mysql/simple_test.rb index 4a73cb1a8..4245128c2 100644 --- a/test/db/mysql/simple_test.rb +++ b/test/db/mysql/simple_test.rb @@ -115,14 +115,6 @@ def test_preserving_time_objects_with_time_with_zone_conversion_to_default_timez super end - # @override - def test_time_with_default_timezone_local - if ENV['CI'] - pend 'TODO: CI: when we start off with UTC the MySQL driver does not handle the time-zone switch right' - end - super - end - # NOTE: all of the above pends are not crucial # we're really pushing the limits with switching TZ in the system ... esp. for the MySQL driver diff --git a/test/db/postgresql/simple_test.rb b/test/db/postgresql/simple_test.rb index da50c42cd..666773739 100644 --- a/test/db/postgresql/simple_test.rb +++ b/test/db/postgresql/simple_test.rb @@ -79,6 +79,16 @@ def test_big_decimal end end + if Time.respond_to?(:zone) + # @override + def test_time_in_dst_change_hour_local + if ENV['CI'] + pend 'TODO: CI: with AR default timezone set to :local PostgreSQL driver will not convert DST missing hour time' + end + super + end + end + def test_encoding assert_not_nil connection.encoding end diff --git a/test/simple.rb b/test/simple.rb index b08d20eaa..491282359 100644 --- a/test/simple.rb +++ b/test/simple.rb @@ -321,7 +321,44 @@ def test_time_with_default_timezone_local end end end + end + + def test_time_in_dst_change_hour_utc + skip "with_system_tz not working in tomcat" if ActiveRecord::Base.connection.raw_connection.jndi? + + with_system_tz 'Europe/Prague' do + Time.use_zone 'Europe/Prague' do + with_timezone_config default: :utc do + id = DbType.connection.insert( + "INSERT INTO db_types (sample_datetime) + values ('2024-03-31 02:30:00')" + ) + saved_time = DbType.find(id).sample_datetime + + assert_equal Time.utc(2024, 3, 31, 2, 30), saved_time + assert_equal 'UTC', saved_time.zone + end + end + end + end + def test_time_in_dst_change_hour_local + skip "with_system_tz not working in tomcat" if ActiveRecord::Base.connection.raw_connection.jndi? + + with_system_tz 'Europe/Prague' do + Time.use_zone 'Europe/Prague' do + with_timezone_config default: :local do + id = DbType.connection.insert( + "INSERT INTO db_types (sample_datetime) + values ('2024-03-31 02:30:00')" + ) + saved_time = DbType.find(id).sample_datetime + + assert_equal Time.local(2024, 3, 31, 3, 30), saved_time + assert_not_equal 'UTC', saved_time.zone + end + end + end end # diff --git a/test/test_helper.rb b/test/test_helper.rb index 178b17e4f..9114d3718 100644 --- a/test/test_helper.rb +++ b/test/test_helper.rb @@ -330,11 +330,18 @@ def with_java_tz(new_tz) java.util.TimeZone.setDefault new_tz org.joda.time.DateTimeZone.setDefault org.joda.time.DateTimeZone.forTimeZone(new_tz) java.lang.System.setProperty 'user.timezone', new_tz.getID + connection_properties = ActiveRecord::Base.remove_connection + prev_config = connection_properties.configuration_hash + new_config = prev_config.deep_dup + new_config[:properties] ||= {} + new_config[:properties]['serverTimezone'] = new_tz.getID + ActiveRecord::Base.establish_connection new_config yield ensure java.util.TimeZone.setDefault old_tz org.joda.time.DateTimeZone.setDefault old_jd old_user_tz ? java.lang.System.setProperty('user.timezone', old_user_tz) : java.lang.System.clearProperty('user.timezone') + ActiveRecord::Base.establish_connection prev_config end end