You have two options, you can either use select or you can create a virtual attribute. I would probably prefer the latter option.
Since TimeZone doesn't directly give you an offset in hours (only in seconds or as a string), you can't use collection_select directly, but you can use select like this (utc_offset is in seconds):
f.select :time_zone, ActiveSupport::TimeZone.us_zones.map { |z| [z.name, z.utc_offset / 1.hour] }
If you use a virtual attribute, use the code you are already using but use :time_zone_name instead of :time_zone and then update your model like this:
def time_zone_name=(value)
time_zone = ActiveSupport::TimeZone.new(value).utc_offset / 1.hour
end
def time_zone_name
# time_zone is a number like -9
ActiveSupport::TimeZone.new(time_zone).name
end
I prefer the last option because it enables you to set the time zone by offset or by name even from rails console or from anywhere where you wish to set it.