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"))