UTC and local timezones in Ruby - ruby

I am located in the Eastern Time (ET) timezone. It is 4 hours behind UTC time. UTC is the standard by which the world regulates clocks and time. I am using Mac OSX.
I was reading this particular article. It seems to suggest that Ruby uses UTC by default if the TZ environment variable is not set. And he gives an example:
ENV["TZ"]
#=> nil
Time.now
#=> 2015-12-08 10:30:00 -0200
ENV["TZ"] = "America/Los_Angeles"
#=> "America/Los_Angeles"
Time.now
#=> 2015-12-08 04:30:14 -0800
Once the environment variable is set, Ruby will then use that timezone. So I tried it in irb:
ENV["TZ"]
=> nil
Time.now
=> 2018-03-29 16:30:21 -0400
ENV["TZ"] = 'Eastern Time (US & Canada)'
=> "Eastern Time (US & Canada)"
Time.now
=> 2018-03-29 20:30:40 +0000
Right now it is a little after 4:30pm or 16:30 in military time. So actually when the TZ environment variable was NOT set, it gave the local time, not UTC time. And after I set the variable to my timezone, it gave a completely wrong time. Why do I not get UTC time when environment variable is not set and why do I get the wrong time when I set the environment variable to my timezone?

This is incorrect. Ruby will pick up the time zone from your computer rather than use UTC by default.
As for why
ENV["TZ"] = 'Eastern Time (US & Canada)'
didn't change the time to eastern is because the right way to do it is:
ENV["TZ"] = 'US/Eastern'
When the value in ENV["TZ"] is not nil, but is not recognized, Ruby defaults to UTC:
Time.now.zone # => "EEST"
ENV["TZ"] = 'Some gibberish'
Time.now.zone # => "UTC"
ENV["TZ"] = 'US/Eastern'
Time.now.zone # => "EDT"

Related

Parsing times with non-local zone abbreviations in Ruby: offset is correct but zone name is lost

Ruby's Time only seems to "remember" my local zone name and UTC. The time object that is created has the correct offset, but #zone is nil. This is easy to see in the console (I am on MDT):
>> Time.parse("12:00 AM MDT")
=> 2018-03-14 00:00:00 -0600
>> Time.parse("12:00 AM MDT").zone
=> "MDT"
>> Time.parse("12:00 AM PST")
=> 2018-03-14 00:00:00 -0800
>> Time.parse("12:00 AM PST").zone
=> nil
>> Time.parse("12:00 AM EDT")
=> 2018-03-14 00:00:00 -0400
>> Time.parse("12:00 AM EDT").zone
=> nil
UTC also works, but that seems to be about it.
Is there a way to preserve the abbreviation for other time zones?
You can not get zone name from Time object, instead you can get the offset value from it. There is no support for timezone abbreviations in ruby
time = Time.parse("12:00 AM PST")
time.gmt_offset
Please note that Time.zone is a feature of Rails' ActiveSupport - it is not provided by TZInfo. ActiveSupport uses TZInfo internally to implement support for time zones.
You can pass zone name to ActiveSupport to construct new time with zone name information.
time = ActiveSupport::TimeZone['Hawaii'].parse('12 AM')
time.zone # 'HST'
You can also use in_time_zone method in rails.
time = Time.parse('12 AM').in_time_zone('Hawaii')
time.zone # 'HST'
Hope it helps !

Determine if a past date falls in the DST range using ruby 2.4

In ruby 2.4 there was a change to how the DateTime#to_time method works. These changes have broken some existing code I had which checked if a given past datetime was in DST
The date below is in the DST range for that year. However, ruby is reporting that dst? == false. I'm pretty stumped here: without using rails how can I test the dst? value of a past datetime?
# 2016-07-27 00:00:00
unix_timestamp = 1469577600
time = Time.at(unix_timestamp).utc
pacific_time = Time.new(time.year, time.month, time.day, 0, 0, 0, "-08:00")
=> 2016-07-27 00:00:00 -0800
pacific_time.dst?
=> false
pacific_time.zone
=> nil
If your local timezone is Pacific Time, then let Time assume it:
irb(main):001:0> unix_timestamp = 1469577600
=> 1469577600
time = Time.at(unix_timestamp).utc
irb(main):004:0> pacific_time = Time.local(time.year, time.month, time.day)
=> 2016-07-27 00:00:00 -0700
irb(main):006:0> pacific_time.dst?
=> true
irb(main):007:0> pacific_time.zone
=> "PDT"
You can also get the local version of your UTC time:
irb(main):015:0> time_local = time.getlocal
=> 2016-07-26 17:00:00 -0700
irb(main):016:0> time_local.dst?
=> true
irb(main):017:0> time_local.zone
=> "PDT"
But, it may be a little brittle to depend on the local timezone without actually specifying it. If you need to display times in another timezone, different than UTC and different than the local one, then maybe Rails' in_time_zone and this related question can help.

Time.parse and DateTime.parse returns different results

Why do these two parse statements return different results?
time = "13:30:0"
DateTime.parse(time).to_time.utc
#=> 2013-10-13 13:30:00 UTC
Time.parse(time).utc
#=> 2013-10-13 11:30:00 UTC
There is no timezone information in the input String. DateTime.parse therefore assumes UTC. Time.parse assumes local time, and I guess you're in UTC+2.
>> time = "13:30:0"
=> "13:30:0"
>> DateTime.parse(time).to_s
=> "2013-10-13T13:30:00+00:00"
>> Time.parse(time).to_s
=> "2013-10-13 13:30:00 +0200"

Change Time.now on server to return different timezone

I have an app deployed on a server where the system time is 7 hours behind UTC. I'm actually in England so I want times displayed in local time GMT (with daylight saving adjusted).
A gem that I'm using, resque, uses Time.now to retrieve the current time. What do I need to configure to get Time.now to return the correct time?
The easiest way would be to set the ENV["TZ"] variable.
> Time.now
=> 2011-05-21 13:13:23 +0200
> ENV["TZ"] = "Europe/London"
=> "Europe/London"
> Time.now
=> 2011-05-21 12:13:55 +0100
Check out some "time warping" gems: http://ruby-toolbox.com/categories/time_warping.html

How do I Convert DateTime.now to UTC in Ruby?

If I have d = DateTime.now, how do I convert 'd' into UTC (with the appropriate date)?
DateTime.now.new_offset(0)
will work in standard Ruby (i.e. without ActiveSupport).
d = DateTime.now.utc
Oops!
That seems to work in Rails, but not vanilla Ruby (and of course that is what the question is asking)
d = Time.now.utc
Does work however.
Is there any reason you need to use DateTime and not Time? Time should include everything you need:
irb(main):016:0> Time.now
=> Thu Apr 16 12:40:44 +0100 2009
Unfortunately, the DateTime class doesn't have the convenience methods available in the Time class to do this. You can convert any DateTime object into UTC like this:
d = DateTime.now
d.new_offset(Rational(0, 24))
You can switch back from UTC to localtime using:
d.new_offset(DateTime.now.offset)
where d is a DateTime object in UTC time. If you'd like these as convenience methods, then you can create them like this:
class DateTime
def localtime
new_offset(DateTime.now.offset)
end
def utc
new_offset(Rational(0, 24))
end
end
You can see this in action in the following irb session:
d = DateTime.now.new_offset(Rational(-4, 24))
=> #<DateTime: 106105391484260677/43200000000,-1/6,2299161>
1.8.7 :185 > d.to_s
=> "2012-08-03T15:42:48-04:00"
1.8.7 :186 > d.localtime.to_s
=> "2012-08-03T12:42:48-07:00"
1.8.7 :187 > d.utc.to_s
=> "2012-08-03T19:42:48+00:00"
As you can see above, the initial DateTime object has a -04:00 offset (Eastern Time). I'm in Pacific Time with a -07:00 offset. Calling localtime as described previously properly converts the DateTime object into local time. Calling utc on the object properly converts it to a UTC offset.
Try this, works in Ruby:
DateTime.now.to_time.utc
You can set an ENV if you want your Time.now and DateTime.now to respond in UTC time.
require 'date'
Time.now #=> 2015-11-30 11:37:14 -0800
DateTime.now.to_s #=> "2015-11-30T11:37:25-08:00"
ENV['TZ'] = 'UTC'
Time.now #=> 2015-11-30 19:37:38 +0000
DateTime.now.to_s #=> "2015-11-30T19:37:36+00:00"
In irb:
>>d = DateTime.now
=> #<DateTime: 11783702280454271/4800000000,5/12,2299161>
>> "#{d.hour.to_i - d.zone.to_i}:#{d.min}:#{d.sec}"
=> "11:16:41"
will convert the time to the utc. But as posted if it is just Time you can use:
Time.now.utc
and get it straight away.

Resources