Set Time Zone Offset in Ruby

Set time zone offset in Ruby

Change the time zone on your OS; Ruby will pick up the change.

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.

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

Change Time zone in pure ruby (not rails)

You can use the Time extensions from Active Support outside of Rails:

require 'active_support/core_ext/time'

t = Time.now
#=> 2014-08-15 15:38:56 +0200

t.in_time_zone('Pacific Time (US & Canada)')
#=> Fri, 15 Aug 2014 06:38:56 PDT -07:00

Now you can do

class Time
def to_pst
in_time_zone('Pacific Time (US & Canada)')
end
end

t = Time.now
#=> 2014-08-15 15:42:39 +0200

t.to_i
#=> 1408110159

t.to_pst
#=> Fri, 15 Aug 2014 06:42:39 PDT -07:00

t.to_pst.to_i
#=> 1408110159

# timestamp does not change!

Additionally you might also want the time extensions on Numeric and Date:

require 'active_support/core_ext/date'
require 'active_support/core_ext/numeric/time'

2.days.from_now
#=> 2014-08-17 15:42:39 +0200

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)

Ruby / Rails - Change the timezone of a Time, without changing the value

Sounds like you want something along the lines of

ActiveSupport::TimeZone.new('America/New_York').local_to_utc(t)

This says convert this local time (using the zone) to utc. If you have Time.zone set then you can of course to

Time.zone.local_to_utc(t)

This won't use the timezone attached to t - it assumes that it's local to the time zone you are converting from.

One edge case to guard against here is DST transitions: the local time you specify may not exist or may be ambiguous.

How can I get the utc offset in Rails?

require 'time'

p Time.zone_offset('EST') #=> -18000 #(-5*60*60)

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



Leave a reply



Submit