Time.now not showing the correct time? - ruby-on-rails

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

Related

Set the right UTC DateTime considering clock changes

I have a ruby on rails app that creates event, from the frontend the date of the event is generated in Mountain Time and then the application transforms it in UTC.
The issue is that since the events are generated in the future sometimes we have issues with the clock change.
Let's say the event should happen:
Day X at 9:30 MT
It would be transformed in:
Day X at 14:30 UTC
But if we create an event in the future that fall in the week the clock change we would have an event configured at the wrong time, because it does not take into consideration the clock change.
Is there a way to generate a UTC dateTime from a specific TimeZone considering if the clock change would happen in that date?
According to Rails API
if your app has its time zone configured as Mountain Time(MT),
Daylight Saving Time(DST) works by default
# application.rb:
class Application < Rails::Application
config.time_zone = 'Mountain Time (US & Canada)'
end
Time.zone # => #<ActiveSupport::TimeZone:0x000000...>
Time.zone.name # => "Mountain Time (US & Canada)"
Time.zone.now # => Tue, 14 Dec 2021 09:46:09 MST -07:00
So if the event date falls after
the DST change, parsing (see ActiveSupport::TimeWithZone)
that date should return the appropiate time
time = Time.zone.parse('2022-03-13 01:00:00') # the parsed datetime is in the same timezone
=> Sun, 13 Mar 2022 01:00:00 MST -07:00
time.dst?
=> false
time = Time.zone.parse('2022-03-13 02:00:00')
=> Sun, 13 Mar 2022 03:00:00 MDT -06:00
time.dst?
=> true
You mention that the application transforms it to UTC. So if I assume,
the correct UTC date is passed to the backend(maybe as an ISO8601 encoded string), you should parse it and convert it to the app time zone by doing something like this:
date = params[:date]
# => "2021-12-14 18:05:05"
utc_datetime = DateTime.parse(date, "%Y-%m-%d %H:%M:%S")
=> 2021-12-14 18:05:05 +0000
mt_datetime = utc_datetime.in_time_zone
=> 2021-12-14 11:05:05 MST -07:00
...
end

How set my timezone correctly to save a record correctly?

In my rails application I'm getting data and saving it by its date for all the records that has the today's date for a later call.
The problem is the data comes in this format "8:05 PM ET"
When I parse it to get it in the date format I get this:
"Mon, 24 Aug 2015 20:05:00 EDT -04:00"
,which is the right date. The thing is when I save it in the database is saved as
"2015-08-25 00:05:00 UTC"
When I request to the db give me all the data from today it doesn't retrieve this record because the date says that record is 25 "tomorrow"** and not **24 "today".
How can I save that record in my database as
today "24" and not as
tomorrow "25"?
My configuration:
application.rb
class Application < Rails::Application
Dir["#{Rails.root}/lib/**/**/*.rb"].each { |f| require f }
config.time_zone = 'Eastern Time (US & Canada)'.freeze
config.active_record.default_timezone = :local
config.active_record.raise_in_transactional_callbacks = true
end
and before save it:
string = '7:05 PM ET'
datetime = DateTime.now
Time.use_zone('Eastern Time (US & Canada)') do
datetime = Time.zone.parse(string)
end
baz.create(time: datetime, foo: 'bar')
when i try to acces it
baz.where(time:Date.today.to_time.beginning_of_day..Date.today.to_time.end_of_day)
In your database, dates are saved in UTC.
But, if you want to retrieve the dates in your own timezone format, you can specify your timezone in the config/application.rb filelike this:
config.time_zone = 'Eastern Time (US & Canada)'.freeze
Then, you can do:
time_now = DateTime.now
time_now_in_my_zone = time_now.in_time_zone(Rails.application.config.time_zone).to_datetime
See ActiveSupport::TimeWithZone
To keep things consistent and saving time in local timezone to database, this has to be set in application.rb
config.active_record.default_timezone = :local
Default timezone is :utc.
See Configuring Active Record for more options.
So, you can use config.active_record.default_timezone = :local setting to save the date in your local format and retrieve it in your format too, and keep things consistent. I think, this answers your question. Let me know if not!
Update
Change:
Time.use_zone('Eastern Time (US & Canada)') do
datetime = Time.zone.parse(string)
end
to:
datetime = Time.now.in_time_zone(Rails.application.config.time_zone).to_datetime
baz.create(time: datetime, foo: 'bar')
You might want to consider studying a little more about time zones.
in your case Mon, 24 Aug 2015 20:05:00 EDT -04:00 is the same date as 2015-08-25 00:05:00 UTC
UTC means the timezone +00:00
A shorter way to achieve that:
Set config.time_zone in your application.rb file.
Use Time.zone.now to save your records.
Example:
Setting 'Buenos Aires' timezone in a Rails application.rb file.
# Set Time.zone default to the specified zone and make Active Record auto-convert to this zone.
config.time_zone = 'Buenos Aires'
Then you can use this to store the properly Time:
Time.zone.now # => Mon, 24 Aug 2015 13:06:21 ART -03:00
If you want to know what time_zone do you need, you can run this: rake time:zones:all
Hope this help :)

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/

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.

How to get time/date string to UTC from local time zone

I have this string:
"2011-12-05 17:00:00"
where this is local time
irb(main):034:0> Time.zone
=> (GMT-08:00) Pacific Time (US & Canada)
Now how to I get a Time object with this in UTC?
These don't work:
Time.local("2011-12-05 17:00:00") => 2011-01-01 00:00:00 +0000
Time.local("2011-12-05 17:00:00").utc => 2011-01-01 00:00:00 UTC
UPDATE:
On my local machine, this works:
Time.parse("2011-12-05 17:00:00").utc
=> 2011-12-06 01:00:00 UTC
but on heroku console it doesn't:
Time.parse("2011-12-05 17:00:00").utc
=> 2011-12-05 17:00:00 UTC
It seems that you should use Time.parse instead of Time.local:
require "time"
Time.parse("2011-12-05 17:00:00").utc
Try this in rails application:
Time.zone = "Pacific Time" # => "Pacific Time"
Time.zone.parse("2011-12-05 17:00:00") # => Mon, 05 Dec 2011 17:00:00 UTC +00:00
Details here
I realized my issue was a little more complicated. I wanted to store the times in the database with no time zone, and no time zone conversions. So I left the server and rails app time zone at UTC.
But when I pulled the times out, I would sometimes need to compare them with the current time in the time-zone that the user was in. So I needed to get Time.zone.now for the user, but again, I have Time.zone set to UTC so no automatic conversions happened.
My solution was to pull out the stored user time zone and apply it to Time.now to get the users local time like this:
class Business < ActiveRecord::Base
def tz
TZInfo::Timezone.get(ActiveSupport::TimeZone::MAPPING[self.time_zone])
end
def now
tz.utc_to_local(Time.zone.now)
end
end
So that I could do something like:
#client.appointments.confirmed_in_future(current_business.now)
-
def confirmed_in_future(date_start = Time.zone.now)
confirmed.where("time >= ?", date_start)
end

Resources