How do I calculate the offset, in hours, of a given timezone from UTC in ruby?
Yes, use TZInfo like this:
require 'tzinfo'
tz = TZInfo::Timezone.get('America/Los_Angeles')
To get the current period:
current = tz.current_period
To find out if daylight savings time is active:
current.dst?
#=> true
To get the base offset of the timezone from UTC in seconds:
current.utc_offset
#=> -28800 which is -8 hours; this does NOT include daylight savings
To get the daylight savings offset from standard time:
current.std_offset
#=> 3600 which is 1 hour; this is because right now we're in daylight savings
To get the total offset from UTC:
current.utc_total_offset
#=> -25200 which is -7 hours
The total offset from UTC is equal to utc_offset + std_offset.
This is the offset from the local time where daylight savings is in effect, in seconds.
Get UTC timezone offset where hour is X in ruby
If you need numerical offsets:
offsets = ActiveSupport::TimeZone.all.map{ |t| t.utc_offset / 3600.0 }.uniq
If you need the string representations:
offset_strs = ActiveSupport::TimeZone.all.map(&:formatted_offset).uniq
Get UTC offset for Timezone at given date via Ruby/tzinfo?
You can use the period_for_local
method. For these examples, I'm using the timezone I live in (America/Sao_Paulo
), in where the offset is -03:00
during winter (March to October) and -02:00
during summer (Daylight Saving Time):
# Sao Paulo timezone
zone = TZInfo::Timezone.new('America/Sao_Paulo')
# date in January (Brazilia Summer Time - DST)
d = DateTime.new(2017, 1, 1, 10, 0)
period = zone.period_for_local(d)
puts period.offset.utc_total_offset / 3600.0
# date in July (Brazilia Standard Time - not in DST)
d = DateTime.new(2017, 7, 1, 10, 0)
period = zone.period_for_local(d)
puts period.offset.utc_total_offset / 3600.0
The output is:
-2.0
-3.0
The utc_total_offset
method returns the offset in seconds, so I divided by 3600 to get the value in hours.
Note that I also used 3600.0
to force the results to be a float. If I just use 3600
, the results will be rounded and timezones like Asia/Kolkata
(which has an offset of +05:30
) will give incorrect results (5
instead of 5.5
).
Note that you must be aware of DST changes, because you can have either a gap or a overlap.
In São Paulo timezone, DST starts at October 15th 2017: at midnight, clocks shift forward to 1 AM (and offset changes from -03:00
to -02:00
), so all the local times between 00:00 and 01:00 are not valid. In this case, if you try to get the offset, it will get a PeriodNotFound
error:
# DST starts at October 15th, clocks shift from midnight to 1 AM
d = DateTime.new(2017, 10, 15, 0, 30)
period = zone.period_for_local(d) # error: TZInfo::PeriodNotFound
When DST ends, at February 18th 2018, at midnight clocks shift back to 11 PM of 17th (and offset changes from -02:00
to -03:00
), so the local times between 11 PM and midnight exist twice (in both offsets).
In this case, you must specify which one you want (by setting the second parameter of period_for_local
), indicating if you want the offset for DST or not:
# DST ends at February 18th, clocks shift from midnight to 11 PM of 17th
d = DateTime.new(2018, 2, 17, 23, 30)
period = zone.period_for_local(d, true) # get DST offset
puts period.offset.utc_total_offset / 3600.0 # -2.0
period = zone.period_for_local(d, false) # get non-DST offset
puts period.offset.utc_total_offset / 3600.0 # -3.0
If you don't specify the second parameter, you'll get a TZInfo::AmbiguousTime
error:
# error: TZInfo::AmbiguousTime (local time exists twice due do DST overlap)
period = zone.period_for_local(d)
How can I get the utc offset in Rails?
require 'time'
p Time.zone_offset('EST') #=> -18000 #(-5*60*60)
How do you get the local timezone offset in +hh:mm format?
strftime
with %z
(:
means hour and minute offset from UTC with a colon):
Time.current.strftime("%:z")
How do I change the zone offset for a time in Ruby on Rails?
I'm using Rails 2.0 before they added the code that makes weppos solution work. Here's what I did
# Silly hack, because sometimes the input_date is in the wrong timezone
temp = input_date.to_time.to_a
temp[8] = true
temp[9] = "Eastern Daylight Time"
input_date = Time.local(*temp)
I break the time down into a 10 element array, change the timezone and then convert the array back into a time.
Rails timezone from offset
You can get a timezone using the []
method on ActiveSupport::TimeZone
. You can either pass a timezone name, hour offset or second offset. For instance:
ActiveSupport::TimeZone["America/Los_Angeles"]
=> (GMT-08:00) America/Los_Angeles
ActiveSupport::TimeZone[-8]
=> (GMT-08:00) America/Los_Angeles
But keep in mind that an offset is not equivalent to a timezone since multiple timezones can be on the same offset on any one day.
Related Topics
Rails with Paypal Permissions and Paypal Express Checkout
Rails Email Error - 530-5.5.1 Authentication Required
Measure and Benchmark Time for Ruby Methods
Ruby Working on Array Elements in Groups of Four
Generating Unique, Hard-To-Guess "Coupon" Codes
Ruby Way to Generate a Hmac-Sha1 Signature for Oauth
What Are the Differences Between Rbenv, Rvm, and Chruby
Is There a Way in Ruby/Rails to Execute Code That Is in a String
Reraise (Same Exception) After Catching an Exception in Ruby
Undefined Method '>' for Nil:Nilclass <Nomethoderror>
Detect Number of Cpus Installed
Ruby: How to Iterate Over an Array of Hashes and Return the Values in a Single String
Does Objective-C Support Mixin Like Ruby
How to Get the Parent's Class Name in Ruby
Generate All Possibles Combinations of an Array with a Length Within a Given Range