diff --git a/lib/time.rb b/lib/time.rb index 679cc82..c57d9ce 100644 --- a/lib/time.rb +++ b/lib/time.rb @@ -61,7 +61,9 @@ class << Time # Numeric time zones that include minutes, such as # -10:00 or +1330 will work, as will # simpler hour-only time zones like -10 or - # +13. + # +13. These numeric time zones may also be prefixed + # with +GMT+ or +UTC+, such as GMT+0900 or + # UTC-05:30. # # Textual time zones listed in ZoneOffset are also supported. # @@ -83,10 +85,10 @@ class << Time def zone_offset(zone, year=nil) off = nil zone = zone.upcase - if /\A([+-])(\d\d)(:?)(\d\d)(?:\3(\d\d))?\z/ =~ zone + if /\A(?:GMT|UTC)?([+-])(\d\d)(:?)(\d\d)(?:\3(\d\d))?\z/ =~ zone off = ($1 == '-' ? -1 : 1) * (($2.to_i * 60 + $4.to_i) * 60 + $5.to_i) - elsif zone.match?(/\A[+-]\d\d\z/) - off = zone.to_i * 3600 + elsif /\A(?:GMT|UTC)?([+-]\d\d)\z/ =~ zone + off = $1.to_i * 3600 elsif ZoneOffset.include?(zone) off = ZoneOffset[zone] * 3600 else diff --git a/test/test_time.rb b/test/test_time.rb index 4054bc4..e1ece64 100644 --- a/test/test_time.rb +++ b/test/test_time.rb @@ -266,6 +266,19 @@ def subtest_xmlschema_whitespaces(method) assert_equal(t, Time.__send__(method, s)) end + def test_zone_offset + assert_equal(9 * 3600, Time.zone_offset("+09:00")) + assert_equal(9 * 3600, Time.zone_offset("+09")) + assert_equal(9 * 3600, Time.zone_offset("GMT+0900")) + assert_equal(9 * 3600, Time.zone_offset("gmt+09:00")) + assert_equal(9 * 3600, Time.zone_offset("UTC+09")) + assert_equal(-(5 * 3600 + 30 * 60), Time.zone_offset("GMT-05:30")) + assert_equal(-(5 * 3600 + 30 * 60), Time.zone_offset("UTC-0530")) + assert_equal(0, Time.zone_offset("GMT")) + assert_nil(Time.zone_offset("GMT+")) + assert_nil(Time.zone_offset("GMT+9:00")) + end + def test_completion now = Time.local(2001,11,29,21,26,35) assert_equal(Time.local( 2001,11,29,21,12), @@ -391,6 +404,17 @@ def test_parse_offset_hour_minute_second assert_equal(t, Time.parse("1200-02-15 BC 14:13:20-00:00:00")) end + def test_parse_gmt_utc_prefixed_offset + t = Time.utc(2026, 10, 10, 1, 47, 0) + # JavaScript's Date#toString format + assert_equal(t, Time.parse("Sat Oct 10 2026 10:47:00 GMT+0900 (Japan Standard Time)")) + assert_equal(9 * 3600, Time.parse("Sat Oct 10 2026 10:47:00 GMT+0900").utc_offset) + assert_equal(t, Time.parse("Fri Oct 09 2026 20:17:00 GMT-0530")) + assert_equal(t, Time.parse("2026-10-10 10:47:00 UTC+09:00")) + assert_equal(t, Time.parse("2026-10-10 10:47:00 UTC+09")) + assert_equal(t, Time.strptime("2026-10-10 10:47:00 GMT+0900", "%Y-%m-%d %H:%M:%S %Z")) + end + def test_parse_custom_offset t = Time.at(-100000000000).utc assert_equal(t, Time.parse("1200-02-15 BC 14:13:20", zone: "UTC"))