How do you convert UTC time to EST in ruby (not using Rails)?

In plain Ruby you may use Time.zone_offset method:

require 'time'

t = Time.now                # 2014-07-30 18:30:00 UTC
t + Time.zone_offset('EST') # 2014-07-30 13:30:00 UTC

The fbonetti's answer leads to the proper UTC to Eastern time conversion while accepted David Unric's answer would give wrong time for 8 months in 2017 (while DST is in effect).

Let's look at the following example:

First we'll need to figure out when DST starts/ends in 2017:

enter image description here

As we can see on March 12th, 2017 deep in the night (2:00am) they change time by adding +1 hour, so they "jump" from 1:59:59am up to 3:00:00am instantaneously! Which means there can not be 2:30am on March 12th, 2017.

Let's choose two UTC timestamps - one before and one after that switch, then we will try to convert those two timestamps from UTC back to Eastern.

First timestamp will be safely far enough from the switch moment:

require 'time'
t1 = Time.parse("2017-03-11 15:00:00 +0000")
=> 2017-03-11 15:00:00 +0000
t1_epoch_s = t1.to_i
=> 1489244400

Second timestamp is just +24 hours from the first one:

t2 = Time.parse("2017-03-12 15:00:00 +0000")
=> 2017-03-12 15:00:00 +0000
t2_epoch_s = t2.to_i
=> 1489330800

Now let us convert t1_epoch_s and t2_epoch_s to Eastern:

method-1: by adding Time.zone_offset('EST')
wrong, gives bad result: 10am for both days :( and offset portion is shown as "+0000" which is also misleading and would refer to completely wrong point in time for people reading our output : ((

Time.at(t1_epoch_s) + Time.zone_offset('EST')
=> 2017-03-11 10:00:00 +0000
Time.at(t2_epoch_s) + Time.zone_offset('EST')
=> 2017-03-12 10:00:00 +0000

method-2: by changing timezone
Good!! Correctly yields 10am and 11am on next day!-)

ENV['TZ'] = 'America/New_York'
Time.at(t1_epoch_s)
=> 2017-03-11 10:00:00 -0500
Time.at(t2_epoch_s)
=> 2017-03-12 11:00:00 -0400
# resetting timezone back
ENV['TZ'] = nil

Basically manually adding Time.zone_offset('EST') is like adding constant and it will give right result for about 4 months (of 12 total) during the year, but then other time you'd have to manually add Time.zone_offset('EDT'), which is another constant. It pretty much same as "a broken clock is right twice a day": )) nasty!

And just for laughter let's see the "slow mo" how proper method handles the actual +1 hour magic jump in time:

ENV['TZ'] = "America/New_York"

Time.at(1489301999 + 0)
=> 2017-03-12 01:59:59 -0500

Time.at(1489301999 + 1)
=> 2017-03-12 03:00:00 -0400

ENV['TZ'] = nil

magic-magic!


In plain ruby, the timezone is determined by the 'TZ' environment variable. You could do something like this:

ENV['TZ'] = 'America/New_York' # set the TZ to Eastern Daylight Time
time = Time.now
time.zone
# => "EDT"

# do stuff

ENV['TZ'] = nil # reset the TZ back to UTC

Tags:

Time

Ruby