This blog is part of our Ruby 2.4 series.
In Ruby, DateTime#to_time and Time#to_time methods can be used to return a Time object.
In Ruby 2.3, these methods convert time into system timezone offset instead of preserving timezone offset of the receiver.
Ruby 2.3
1 2> datetime = DateTime.strptime('2017-05-16 10:15:30 +09:00', '%Y-%m-%d %H:%M:%S %Z') 3 #=> #<DateTime: 2017-05-16T10:15:30+09:00 ((2457890j,4530s,0n),+32400s,2299161j)> 4> datetime.to_time 5 #=> 2017-05-16 06:45:30 +0530 6 7> time = Time.new(2017, 5, 16, 10, 15, 30, '+09:00') 8 #=> 2017-05-16 10:15:30 +0900 9> time.to_time 10 #=> 2017-05-16 06:45:30 +0530 11
As you can see, DateTime#to_time and Time#to_time methods return time in system timezone offset +0530.
Ruby 2.4 fixed DateTime#to_time and Time#to_time.
Now, DateTime#to_time and Time#to_time preserve receiver's timezone offset info.
Ruby 2.4
1 2> datetime = DateTime.strptime('2017-05-16 10:15:30 +09:00', '%Y-%m-%d %H:%M:%S %Z') 3 #=> #<DateTime: 2017-05-16T10:15:30+09:00 ((2457890j,4530s,0n),+32400s,2299161j)> 4> datetime.to_time 5 #=> 2017-05-16 10:15:30 +0900 6 7> time = Time.new(2017, 5, 16, 10, 15, 30, '+09:00') 8 #=> 2017-05-16 10:15:30 +0900 9> time.to_time 10 #=> 2017-05-16 10:15:30 +0900 11
Since this is a breaking change for Rails application upgrading to ruby 2.4, Rails 4.2.8 built a compatibility layer by adding a config option. ActiveSupport.to_time_preserves_timezone was added to control how to_time handles timezone offsets.
Here is an example of how application behaves when to_time_preserves_timezone is set to false.
1> ActiveSupport.to_time_preserves_timezone = false 2 3> datetime = DateTime.strptime('2017-05-16 10:15:30 +09:00', '%Y-%m-%d %H:%M:%S %Z') 4 #=> Tue, 16 May 2017 10:15:30 +0900 5> datetime.to_time 6 #=> 2017-05-16 06:45:30 +0530 7 8> time = Time.new(2017, 5, 16, 10, 15, 30, '+09:00') 9 #=> 2017-05-16 10:15:30 +0900 10> time.to_time 11 #=> 2017-05-16 06:45:30 +0530
Here is an example of how application behaves when to_time_preserves_timezone is set to true.
1> ActiveSupport.to_time_preserves_timezone = true 2 3> datetime = DateTime.strptime('2017-05-16 10:15:30 +09:00', '%Y-%m-%d %H:%M:%S %Z') 4 #=> Tue, 16 May 2017 10:15:30 +0900 5> datetime.to_time 6 #=> 2017-05-16 10:15:30 +0900 7 8> time = Time.new(2017, 5, 16, 10, 15, 30, '+09:00') 9 #=> 2017-05-16 10:15:30 +0900 10> time.to_time 11 #=> 2017-05-16 10:15:30 +0900