How to convert UTC to EST by taking care of daylight savings - ruby

I am pulling the following output from a website using an API call:
out_string += "Incident Created :" + nextOncall_result['incident']['created_at'].to_s + "\n"
"created_at" gives the time when an incident was created. The website is in UTC, and I want to convert it to EST by taking care to daylight savings.
Please help me. Please change the code if possible.

In rails you can do:
nextOncall_result['incident']['created_at'].in_time_zone('EST')
UPD
require 'tzinfo'
offset = TZInfo::Timezone.get('EST').current_period.offset.utc_total_offset
time_with_dst_in_utc = nextOncall_result['incident']['created_at'] + offset
res = time_with_dst_in_utc.strftime('%d/%m/%Y %m:%S')

Related

Converting the time in IST to EST using ruby

I'm trying to convert the time which is in IST to EST using Ruby(NOT Rails). I tried different ways. But its returning the time in UTC. here is the example.
08/08/2014 01:45 AM
Is there any way to convert the above date into EST.
Try this
require 'time'
ist = Time.parse('08/08/2014 01:45 AM +05:30')
p ist
est = ist.getlocal("-05:00")
p est
Output
2014-08-08 01:45:00 +0530
2014-08-07 15:15:00 -0500
[Finished in 0.1s]
First I would check out a couple methods in the Time class in ruby's documentation http://ruby-doc.org/core-2.2.1/Time.html#method-i-2B
Specifically Time#now Time#strftime Time#-
To start off I am going to assume that you are in Indian Standard Time and would like to know what time it is for your friend in Eastern Standard Time. According to google.com.. IST is 9 and 1/2 hours ahead of EST. Which means you need to get your current time in IST and subtract 9.5 hours. See if this is what your looking for..
#Simple Method That Takes a Time Argument
#If you read correctly, Time#- uses seconds.
def to_est(ist)
(ist - 34200).strftime("%m/%d/%Y %I:%M%p")
end
#Calling the method
puts to_est(Time.now)
%m = Month
%d = Day
%Y = Year
%I = Hour
%M = Minute
%p = Meridian Indicator

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

I am capturing the current time like so:
Time.now
My server runs on UTC. How can I convert the time to EST without using any Rails libraries? I am guessing some sort of offset but not sure how it works per say.
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:
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
If you don't mind using a gem,
require 'tzinfo'
tz = TZInfo::Timezone.get('US/Eastern')
Time.now.getlocal(tz.current_period.offset.utc_total_offset)
Credit: https://stackoverflow.com/a/42702906/2441263

Rails Time Zone and cron scheduling

I have an AWS server that runs daily cron jobs reporting on our user base. I want to ensure my report is run for the full day the previous day in MST. Currently I use this as the code for the data quering
Time.new(Time.now.year, Time.now.month, Time.now.day).yesterday.beginning_of_day.in_time_zone('MST)..Time.new(Time.now.year, Time.now.month, Time.now.day).yesterday.end_of_day.in_time_zone('MST)
I read it is bad practice to use Time.now as that is the system (UTC) time? I am wondering if what I am doing is a big no no or if there is a more efficient way?
thank you!
Mountain Standard Time is 7 hours behind UTC, so when you capture all the data points from the day of July 22rd in MST, you want the UTC times to be from 7/22 at 7:00AM UTC to 7/23 at 7:00AM UTC.
I don't think your code is correct because you are calling in_time_zone("MST") after beginning_of_day.
When you run this code on a server that is on UTC, the evaluated times are different:
>> Time.new.yesterday.beginning_of_day.in_time_zone('MST').utc
=> 2013-07-22 00:00:00 UTC
>> Time.new.in_time_zone("MST").yesterday.beginning_of_day.utc
=> 2013-07-22 07:00:00 UTC
Here is how you can determine the start and end times properly:
>> t = Time.new
=> 2013-07-23 19:45:10 +0000
>> start_time = t.in_time_zone("MST").yesterday.beginning_of_day
=> Mon, 22 Jul 2013 00:00:00 MST -07:00
>> end_time = t.in_time_zone("MST").yesterday.end_of_day
=> Mon, 22 Jul 2013 23:59:59 MST -07:00
When we convert the start and end times to UTC, we get the desired result.
>> start_time = t.in_time_zone("MST").yesterday.beginning_of_day.utc
=> 2013-07-22 07:00:00 UTC
>> end_time = t.in_time_zone("MST").yesterday.end_of_day.utc
=> 2013-07-23 06:59:59 UTC
I don't know what you are trying to do, but
Time.new(Time.now.year, Time.now.month, Time.now.day)
is definitely a terrible code fragment. For example, if the time lag between the execution time of Time.now.year and that of Time.now.month overlaps the moment of the change of the year, then the time object created with the main Time.new will be neither of the two moments. If you want to get the current time, just do
Time.new
or
Time.now
If you are trying to create a time range calculated out of a single time, then whatever your code should be, create time only once:
t = Time.now
and use that in the rest of your code:
t.some_method..t.some_other_method

Working with Rails Timezones?

Working on a 3 week new registration chart for metrics, I have the following code:
(3.weeks.ago.to_date..Date.today).map { |date| Metrics.registrations_on(date) }
In Metrics.rb:
def self.registrations_on(date)
date = date.midnight
end_date = date + 24.hours
User.where(:created_at => date..end_date).count
end
Before the day is done here in California, a new day's numbers are already starting to increase. The created_at timestamp is UTC as well.
I'd like to be able to see the stats from today, using our time zone. With my data already saved as UTC I'm curious as to how about accomplishing this.
Open config/application.rb, find config.time_zone, and assign it with appropriate value:
config.time_zone = 'Pacific Time (US & Canada)'
Restart your app, and all ruby date/time operation should be adjusted automatically to your time zone.
For a list of all supported time zone strings, use:
bundle exec rake time:zones:all

How do I calculate the offset, in hours, of a given timezone from UTC in ruby?

I need to calculate the offset, in hours, of a given timezone from UTC in Ruby. This line of code had been working for me, or so I thought:
offset_in_hours = (TZInfo::Timezone.get(self.timezone).current_period.offset.utc_offset).to_f / 3600.0
But, it turns out that was returning to me the Standard Offset, not the DST offset. So for example, assume
self.timezone = "America/New_York"
If I run the above line, offset_in_hours = -5, not -4 as it should, given that the date today is April 1, 2012.
Can anyone advise me how to calculate offset_in_hours from UTC given a valid string TimeZone in Ruby that accounts for both standard time and daylight savings?
Thanks!
Update
Here is some output from IRB. Note that New York is 4 hours behind UTC, not 5, because of daylight savings:
>> require 'tzinfo'
=> false
>> timezone = "America/New_York"
=> "America/New_York"
>> offset_in_hours = TZInfo::Timezone.get(timezone).current_period.utc_offset / (60*60)
=> -5
>>
This suggests that there is a bug in TZInfo or it is not dst-aware
Update 2
Per joelparkerhender's comments, the bug in the above code is that I was using utc_offset, not utc_total_offset.
Thus, per my original question, the correct line of code is:
offset_in_hours = (TZInfo::Timezone.get(self.timezone).current_period.offset.utc_total_offset).to_f / 3600.0
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.

Resources