Rails 3 time zone issue (database is 5 hours off) - ruby-on-rails

So in my rails console. This is what I get if I check Time.now:
1.9.2p290 :014 > Time.now
=> 2012-02-06 01:00:43 -0500
1.9.2p290 :015 > Time.now.zone
=> "EST"
In my application.rb I have set the time zone as follows:
config.time_zone = 'Eastern Time (US & Canada)'
config.active_record.default_timezone = 'Eastern Time (US & Canada)'
However, when I store something into the database, it is still 5 hours off:
1.9.2p290 :011 > event = Event.new(:message => 'blah', :status_id => 1, :service_id => 1, :created_at => Time.now)
=> #<Event id: nil, message: "blah", status_id: 1, service_id: 1, created_at: "2012-02-06 05:55:26", updated_at: nil>
Why is it five hours off? If I compare the zones of each, this is what I get:
1.9.2p290 :016 > event.created_at.zone
=> "EST"
1.9.2p290 :017 > Time.now.zone
=> "EST"

Ok I fixed the issue. Looks like this line in application.rb was causing a problem.
config.active_record.default_timezone = 'Eastern Time (US & Canada)'
ActiveRecord will use the local time zone by default according to the ActiveRecord::Timestamp docs. http://api.rubyonrails.org/classes/ActiveRecord/Timestamp.html

in AR 3.2.1, you must either set this option to :utc or :local, or you will receive this warning:
warning: :database_timezone option must be :utc or :local - defaulting to :local

Related

What's wrong with Rails's Date

I ran into this non-sense problem this morning in Rails 3.2 console. I'm under MacOS 10.10, my timezone is +7.
Loading development environment (Rails 3.2.12)
irb(main):001:0> Date.today
=> Sun, 16 Nov 2014
irb(main):002:0> Date.yesterday
=> Fri, 14 Nov 2014
irb(main):003:0>
Everything is fine with original Ruby Date:
irb(main):006:0> Date.today
=> #<Date: 2014-11-16 ((2456978j,0s,0n),+0s,2299161j)>
irb(main):007:0> Date.today.prev_day
=> #<Date: 2014-11-15 ((2456977j,0s,0n),+0s,2299161j)>
irb(main):008:0>
From the bug report here: https://rails.lighthouseapp.com/projects/8994/tickets/6410#ticket-6410-8
This is a subtle one - Date.yesterday uses Date.current which will use the time zone whereas Date.today doesn't. If you set your time zone to one where it's tomorrow already (e.g. Europe/Berlin as I type this) then you can get Date.today == Date.yesterday:
Time.zone = "Europe/London"
=> "Europe/London"
Date.today == Date.yesterday
=> false
Time.zone = "Europe/Berlin"
=> "Europe/Berlin"
Date.today == Date.yesterday
=> true

Ruby upgrade (from 1.8.7) on Rails 3.0.20 application causing time zone weirdness

I'm upgrading an big, old, clunky Rails application's Ruby (mostly so I don't have to re-install REE on my reformatted laptop) and I'm getting bitten pretty badly by timezone issues. Basically, pulling datetimes out of the database is not converting them to local time correctly:
New System - Ruby 2.1.2, Ubuntu 14.04
>> Time.zone.name
=> "Central Time (US & Canada)"
>> ActiveRecord::Base.time_zone_aware_attributes
=> true
>> ActiveRecord::Base.default_timezone
=> :utc
>> Transaction.last.created_at
=> 2014-07-15 02:09:02 UTC
>> Transaction.last.created_at_before_type_cast
=> 2014-07-15 02:09:02 UTC
>> Transaction.last.created_at.localtime
=> 2014-07-14 21:09:02 -0500
>> exit
$ date
Mon Jul 14 22:27:50 CDT 2014
Old System - REE, Ubuntu 12.04
>> Transaction.last.created_at
=> Mon, 14 Jul 2014 22:03:11 CDT -05:00
>> Transaction.last.created_at_before_type_cast
=> Tue Jul 15 03:03:11 UTC 2014
>> Transaction.last.created_at.localtime
=> Mon Jul 14 22:03:11 -0500 2014
As you can see, I've ensured that time_zone_aware_attributes is set, the zone is set (I set it in the environment.rb), and ActiveRecord is storing the times in UTC (as expected). I'm so stumped on this. Anyone have any ideas?
Update
before :all do
#current_tz = Time.zone
Time.zone = 'Pacific Time (US & Canada)'
end
after :all do
Time.zone = #current_tz
end
it 'should report time as Pacific time' do
shift = FactoryGirl.create(:shift)
new_obj = Transaction.create(shift: shift, time: DateTime.new(2013, 3, 31, 0, 0, 0, 0), amount: 0)
new_obj.reload
I18n.localize(new_obj.time, format: :timeonly).should_not == '12:00 am' #We created it with a UTC date, but it should get I18n'd to Pacific time
end
#en.yml
time:
formats:
timeonly: "%l:%M %p"
The above test is also failing. The I18n stuff seems totally broken.
Update 2
I seem to have isolated the problem to 1.9.3 -> 2.1. Using 1.9.3 is fine, I suppose, and I guess I'll just run that on the new server until I upgrade Rails. Sad. I'd still love to hear any suggestions about fixes.
Try using the I18n helpers to format/offset your time output - and force timezone (if needed)
puts I18n.localize(Transaction.last.created_at, format: :long)
Or
Time.use_zone("Central Time (US & Canada)") do
puts I18n.localize(Transaction.last.created_at, format: :long)
end
I recommend you set your default Time.zone to UTC as well and update it for each user explicitly as needed - here is a blog post that might be helpful: http://jessehouse.com/blog/2013/11/15/working-with-timezones-and-ruby-on-rails/

Time.now not showing the correct time?

I have set my server time on UTC and and my production.rb to config.time_zone = 'Pacific Time (US & Canada)' as my app is using Pacific time.
In ruby console, Time.now is showing UTC and not Pacific!
Is this normal?
How to make sure my app is using PST?
Thanks!
Mel
I had my own confusion when using timezones in Ruby without Rails and then I discovered an article that shed some clarification. Ruby is packaged with the Date and Time classes. These classes exist without Rails:
require "time"
Time.parse("Dec 8 2015 10:19")
#=> 2015-12-08 10:19:00 -0200
Date.parse("Dec 8 2015")
#=> #<Date: 2015-12-08>
Time.new(2015, 12, 8, 10, 19)
#=> 2015-12-08 10:19:00 -0200
Date.new(2015, 12, 8)
Ruby by default uses the timezone defined in /etc/localtime on Unix-like systems, unless you modify the TZ environmental variable like so:
ENV["TZ"] = 'US/Eastern'
It is recommended to do this if your system time is not UTC time, then you can change the environment to UTC:
Time.now
=> 2018-03-29 20:17:39 -0400
ENV['TZ']
=> nil
ENV['TZ'] = 'UTC'
=> "UTC"
Time.now
=> 2018-03-30 00:17:59 +0000
Now I know that Rails has its own configuration, which you may find in application.rb:
config.time_zone = 'Eastern Time (US & Canada)'
config.active_record.default_timezone = :local
Rails will use this time zone configuration in your application, and it will ignore the TZ environment variable or even your system defaults.
But what you need to understand is Ruby will ignore the Rails timezone configuration, even within the context of the Rails environment! So then how do you take advantage of the Rails configuration and not the Ruby configuration? Rails has its own methods defined in ActiveSupport. These methods will generate date and time objects from the ActiveSupport::TimeWithZone. But you need to understand how to use these methods:
Use Time.current instead of Time.now.
Use Date.current instead of Date.today.
And the example:
rails c
Time.now
=> 2018-03-29 20:20:14 -0400
ENV['TZ']
=> nil
ENV['TZ'] = 'UTC'
=> "UTC"
Time.now
=> 2018-03-30 00:20:35 +0000
Time.current
=> Thu, 29 Mar 2018 20:20:40 EDT -04:00

How to get the time zone abbreviation from Time.now?

Time.now.strftime('%Z') returns 'Mountain Daylight Time' for me. I'd like to get MDT.
What's the correct way to get the time zone abbreviation?
Just in case anyone suspected I was misleading them:
irb(main):001:0> Time.now.strftime('%Z')
=> "Mountain Daylight Time"
irb(main):002:0> Time.now.zone
=> "Mountain Daylight Time"
irb(main):003:0> Time.now.in_time_zone('Mountain Time (US & Canada)').zone
=> "MDT"
Ran a few things, I'd say try using Time.now.zone
#This is working for me, but not for you. I'm not sure why (although others might!)
$ > Time.now.strftime('%Z')
=> "CEST"
#This gives UTC time which is useful, but not what you're after
$ > Time.zone
=> #<ActiveSupport::TimeZone:0x00000103049918 #name="UTC", #utc_offset=nil, #tzinfo=#<TZInfo::TimezoneProxy: Etc/UTC>, #current_period=nil>
$ > Time.zone.now
=> Sat, 05 Oct 2013 09:11:01 UTC +00:00
$ > Time.zone.now.zone
=> "UTC"
#This will (perhaps) return what you want.
#It's possible that you'll still just get "Mountain Daylight Time"
$ > Time.now
=> 2013-10-05 11:12:09 +0200
$ > Time.now.zone
=> "CEST"

Rails timezone activerecord

My application.rb:
config.time_zone = 'Moscow'
config.time_zone = "(GMT+04:00) Moscow"
config.active_record.default_timezone = 'Moscow'
config.active_record.default_timezone = :local
When i run this commands, i get:
1.9.3-p362 :001 > Time.now
=> 2013-02-14 14:18:42 +0400
1.9.3-p362 :002 > Time.zone.now
=> Thu, 14 Feb 2013 10:18:52 UTC +00:00
So in db i see 10:18:52 UTC +00:00.
But what and how to configure, to see such time, as in Time.Now? (when i insert new row to db i must see time, as given by Time.now, what to configure?)
Server's time is Moscow....
also db is mysql
You can use local time like this:
> current_time = Time.now.utc
=> 2013-02-14 15:15:58 UTC
> current_time .localtime
=> 2013-02-14 10:15:58 -05 hours
You can use also:
Time.now.utc.in_time_zone("Moscow")
But for the answer to your question, the solution could be to set it like this:
config.time_zone = 'Moscow' (don't set this - delete this line)
config.active_record.default_timezone = :local
And also you can use your local time something like this:
Time.local_time
I hope some of this approaches might help you
In your application.rb include these lines:
config.time_zone = 'Moscow'
config.active_record.default_timezone = 'Moscow'
Now that you have set the time zone:
Time.now
=> 2013-02-14 11:14:46 +0000
Time.current
=> Thu, 14 Feb 2013 15:14:48 MSK +04:00
user = User.create(name: 'test')
=> #<User id: 6, name: "test", created_at: "2013-02-14 11:15:00", updated_at: "2013-02-14 11:15:00">
user.created_at
=> Thu, 14 Feb 2013 15:15:00 MSK +04:00
As you can see, despite the fact that rails stores the time as UCT +0000 (very clever btw), the rails interface is providing the required offset. If you call any object, such as user.created_at it will offset the database time to return the zone time.
It is very useful, because it allows the configuration of different time zones for different users. The time will be stored without offset, but each user will get its equivalent time zone.
Time.now return +00:00, doesn't matter your time zone.
Time.current is the same as Time.zone.now.

Resources