Rails: print UTC time by default - ruby-on-rails

I have a non-ActiveRecord server which is sending data to another service. That server expects to receive instructions including UTC in the format: "%Y-%m-%d %H:%M:%S.%L". I already have an time_format.rb initializer that overrides Time::DATE_FORMATS[:default] Is there a way I can configure my server so that Time.now.to_s will by default print UTC time, without me having to specify Time.now.utc every time I call it? I'm using ruby 2.0.0 and Rails 4.
I tried adding config.time_zone = 'London' to config/application.rb but that did not work.

I don't think ActiveRecord should have anything to do with it, but maybe I'm misunderstanding. Like Sergio said, set your applications timezone to UTC.
Here's my Rails app. My computer is in PST. My Rails app is set to UTC.
> Time.now
=> 2014-01-22 21:52:38 -0800
> Time.zone.name
=> "UTC"
> Time.zone.now
=> Thu, 23 Jan 2014 05:52:43 UTC +00:00
> Time.now.utc
=> 2014-01-23 05:52:45 UTC
I would strongly advise not overriding Time.now. That can only lead to the dark side.

A general purpose solution that works for any Ruby application:
module TimeClassExtensions
def now
super.utc
end
end
Time.singleton_class.prepend(TimeClassExtensions)

Related

Set activerecord default timezone to a specific timezone

I'm using a Rails application to access a database from a legacy application. This application stores all datetime fields using Europe/Madrid timezone.
I tried to set this in my application.rb:
config.time_zone = 'Madrid'
config.active_record.default_timezone = :local
Unfortunately it didn't worked as I expected. It looks like Rails is using the timezone of my system ( America/Sao_Paulo ). So a date that is stored as:
2015-09-09 18:38:01
Will be shown with a difference of 5 hours in Rails:
2015-09-09 23:38:01
Which is the difference between São Paulo and Madrid. It should show 18:38:01 in Rails too since my app's default timezone is Madrid.
Is there a way to force the ActiveRecord timezone without changing my OS timezone?
--- Edit ---
Here is the output that I get:
2.1.3 :004 > Time.zone.name
=> "Madrid"
2.1.3 :005 > LogSent.last.sent_date
LogSent Load (0.4ms) SELECT `log_sent`.* FROM `log_sent` ORDER BY `log_sent`.`id` DESC LIMIT 1
=> Wed, 09 Sep 2015 23:38:01 CEST +02:00
I'm expecting "Wed, 09 Sep 2015 18:38:01 CEST +02:00" which is the value stored in database, in Madrid timezone.
I know this was 3 years ago, but maybe somebody else will have the same question like I did.
When you put config.active_record.default_timezone = :local in your configuration, AR assumes that DB has local timezone, local here meaning the one on your computer. It's pretty hard to change that behaviour, you'd have to monkey-patch both ActiveRecord and ActiveModel.
Trick, however, is to convince Ruby (not Rails) that Madrid is your local time. You can do that by setting TZ environment variable to Madrid.
You can put in your config/initializers/timezone.rb the following
ENV["TZ"] = "Madrid"
Or just set the env variable before running the server as normal,
and don't forget about config.active_record.default_timezone = :local.
This way all values read and written to DB will be in Madrid timezone
How do you save sent_date attribute?
Remember that if you use DateTime.now, it will retrieve the current DateTime of your system (Sao Paulo time). Instead, you should use Time.zone.now, which will retrieve the current DateTime configured in application.rb

Weird Behaviors of datetime(timezone) in Rails application

In our rails 3.2 application, we have configured,
config.time_zone = 'London'
config.active_record.default_timezone = :local
And in postgresql also configured timezone as "Europe/London".
For the past one week, our application datetime field is not working properly with timezone.
For an example, If we create an reminder start_date at 2015-08-18 10AM. it creates `2015-08-18 10:00:00 in postgres database.
when displaying in template,
reminder start date: 2015-08-18 10AM (2015-08-18 10:00:00 +0100 )
BUT,(not always) now frequently its showing UTC time.
reminder start date: 2015-08-18 9AM (2015-08-18 09:00:00 UTC )
it could not be reproduced in development.
If we restart the unicorn server then it is not occurring for 4 hours.
anyone faced this kind of problem?
I fixed this issue, by adding around filter in ApplicationController.
around_filter :use_time_zone
private
def use_time_zone(&block)
Time.use_zone('London', &block)
end
So, whenever the default timezone changed to UTC, it will override and set as BST.

Manage timezone properly in rails

I have a backend written in RoR, and I need to manage many requests from different peers around the world. I have the following questions:
Is it proper to change the config.timezone for each request ?
If yes:
Assuming that 2 requests arrive on my server at the same time. Will the timezone be different for both ? (Means, will there be two differents config.timezone ?)
I don't find any way to set the config timezone with desired UTC, like Time.zone = 'UTC+X'
If no:
Do you know any way to manage it easily and properly ? I have a lot of timezone operations to do, then it would be easier to set it in configuration.
Based on the answers to this question:
Convert Time from one time zone to another in Rails
It seems like using config.timezone is a bad idea due to threading issues.
I would recommend using the ActiveSupport TimeZone and TimeWithZone classes.
This allows you to do things along the lines of:
# Return the simultaneous time in Time.zone or the specified zone
Time.now.in_time_zone # => Tue, 13 Jul 2010 01:20:55 EDT -04:00
Time.now.in_time_zone(Time.zone) # => Tue, 13 Jul 2010 01:20:55 EDT -04:00
Time.now.in_time_zone("Asia/Vladivostok") # => Tue, 13 Jul 2010 16:20:55 VLAST +11:00
Time.now.in_time_zone(-3.hours) # => Tue, 13 Jul 2010 02:20:55 BRT -03:00
# Switch to a given timezone within a block
Time.use_zone "Asia/Vladivostok" do
Time.zone.now # => Tue, 13 Jul 2010 16:20:55 VLAST +11:00
end
Sample code is from http://ofps.oreilly.com/titles/9780596521424/active-support.html
Take a look under 'Time Zone Conversions'
Not a good idea to change config.timezone for each request, but yes, timezone should be handled on per request basis.
Check out the excellent & comprehensive blogpost titled Working with time zones in Ruby on Rails by the folks at elabs for advice on how to deal with multiple timezones.
Ryan Bates' revised version of Time Zones RailsCasts episode is another good resource.

Model's datetime field is stored differently on heroku from localhost

Steps:
On my localhost server I select the time Jan 18, 2013 10 am - 11 am in my browser located in the Pacific time zone. I then select the exact same time on my production server on heroku.
As you can see the outputs of what is saved to the database are different. I want production to behave as localhost and take into account the timezone when storing the time as UTC. What is causing this? The heroku server is in EST, but that does not account for this behavior.
Controller:
def create
puts params[:event][:starts_at]
#event = Event.create!(params[:event])
puts #event.starts_at
end
Output Localhost:
Fri Jan 18 2013 10:00:00 GMT-0800 (PST)
2013-01-18 18:00:00 UTC
Output Heroku (production):
Fri Jan 18 2013 10:00:00 GMT-0800 (PST)
2013-01-18 10:00:00 UTC
Schema:
t.datetime "starts_at"
Env:
Ruby on Rails 3.2.11
Ruby 1.9.3
Postgres
Background on how PostgreSQL deals with date/time
I think your issue is covered in this answer from another SO question:
Ignoring timezones altogether in Rails and PostgreSQL
Specifically this answer:
https://stackoverflow.com/a/9576170/33204
Use this query for time in UTC format:
SELECT * FROM tbl WHERE time_col > (now() AT TIME ZONE 'UTC')::time
Use this query for time in local timezone:
SELECT * FROM tbl WHERE time_col > now()::time
Rails & ActiveRecords & date/time
This rails/rails github issue also discusses it:
ActiveRecord converts time to default zone on write; assumes UTC on read
There is a comment by pixeltrix which says the following:
#deathbob sorry for the late reply - the accepted values for
config.active_record.default_timezone are either :utc or :local. If
you set it to something other than :utc it will assume :local so what
you're seeing is the expected behavior.
To fix the time in ActiveRecords so that it is always dealt with as UTC you can set the following variable:
config.active_record.default_timezone = :utc
The solution by #slm of config.active_record.default_timezone = :utc did not work for me. Rails was still writing with local and reading with UTC on Heroku.
So I then tried:
config.time_zone = 'Sydney'
config.active_record.default_timezone = :local
Which was still working fine in development but caused the datetime values to now be read in a UTC format from postgres on Heroku.
My temporary workaround solution was to set the default timezone on Heroku with:
heroku config:add TZ="Australia/Sydney"
This is only a temporary solution as I would like my app to use UTC. I have posted to the rails/github issue mentioned by #slm for clarification. I will update my answer when I find a more concrete solution.

Rails: Hack Time.now to alias Time.current

I just currently changed my application to use the PST time zone. However, a lot of my application has code that uses Time.now which is still stuck in UTC:
irb(main):012:0> Time.now
=> 2012-12-27 05:03:16 +0000
Time.current on the other hand, seems to have the correct timezone usage:
irb(main):013:0> Time.current
=> Wed, 26 Dec 2012 21:03:42 PST -08:00
Instead of going through my entire app and changing every instance of Time.now, does it make sense to somehow alias Time.now to use Time.current instead? Is there a better way of handling this in my application so I don't have to modify everywhere I use Time.now since it is not using my app's configured timezone?
From my point of view, this kind of monkey patching should be avoided: Using 'Replace All In Path' Time.now => Time.current is not any harder to do in almost any editor, but you save your debugging time in future hunting some weird bugs in 3rd parties or people working on the same project with your.
If you are using ubuntu, try find/replace with perl
perl -pi -e 's/Time\.now/Time\.current/' *

Resources