If you are working with Ruby On Rails and you want to change time zone per request and reset it back after finishing the request. You can use Time.use_zone
to set the time zone for the user (document: http://api.rubyonrails.org/classes/Time.html#method-i-use_zone)
The following is what I have tested in Rails 4.1.
First, It is recommended to set the sane default for config.time_zone (in config/application.rb), I set to "Mumbai" (UTC+5.30) for instance. (to list time zones, you can use command bundle exec rake time:zones:all
)
module MyApp
class Application < Rails::Application
config.time_zone = 'Mumbai'
end
end
In your project, run rails g model User name:string time_zone:string
And bundle exec rake db:migrate
Then, create some test users via rails console, run rails c
Loading development environment (Rails 4.1.4)
irb(main):001:0> first_user = User.create!(name: 'zdk', time_zone: 'Bangkok')
(0.1ms) begin transaction
SQL (0.4ms) INSERT INTO "users" ("created_at", "name", "time_zone", "updated_at") VALUES (?, ?, ?, ?) [["created_at", "2014-07-31 09:21:13.750710"], ["name", "zdk"], ["time_zone", "Bangkok"], ["updated_at", "2014-07-31 09:21:13.750710"]]
(0.6ms) commit transaction
=> #<User id: 1, name: "zdk", time_zone: "Bangkok", created_at: "2014-07-31 09:21:13", updated_at: "2014-07-31 09:21:13">
irb(main):002:0> second_user = User.create!(name: 'joe', time_zone: 'London')
(0.1ms) begin transaction
SQL (0.8ms) INSERT INTO "users" ("created_at", "name", "time_zone", "updated_at") VALUES (?, ?, ?, ?) [["created_at", "2014-07-31 09:21:31.299606"], ["name", "joe"], ["time_zone", "London"], ["updated_at", "2014-07-31 09:21:31.299606"]]
(1.9ms) commit transaction
=> #<User id: 2, name: "joe", time_zone: "London", created_at: "2014-07-31 09:21:31", updated_at: "2014-07-31 09:21:31">
irb(main):003:0>
Try to query what we just created, you can see that it uses time zone that you have set in Application config (config.time_zone).
The output:
irb(main):003:0> first_user.created_at
=> Thu, 31 Jul 2014 14:51:13 IST +05:30
irb(main):005:0> second_user.created_at
=> Thu, 31 Jul 2014 14:51:31 IST +05:30
And how to handle per request basis time zone using Time.zone.
Go to your ApplicationController (app/controllers/application_controller.rb file).
Create a method that set time zone called by around_filter
( More details: http://www.elabs.se/blog/36-working-with-time-zones-in-ruby-on-rails ). I also create hello action will be routed from root url. Like so:
class ApplicationController < ActionController::Base
protect_from_forgery with: :exception
around_filter :set_time_zone
def set_time_zone
if true #if user loggin ?
@user = User.first #Change to User.last to see the result.
Time.use_zone(@user.time_zone) { yield }
else
yield
end
end
def hello
render plain: "Hello, user: #{@user.name}. Created: #{@user.created_at}"
end
end
Routing application uri to your controller method by editing your config routes (config/routes.rb) to have following this
Rails.application.routes.draw do
root 'application#hello'
end
If you set everything correctly. You should have the output in this format
for the first user: Hello, user: zdk. Created: <Date> <Time> +0700
for the second user: Hello, user: joe. Created: <Date> <time> +0100
In summary, the flow is something like:
+------------+
| APP |
+------------+
+ Use the Time.zone value instead if it's set
| ^
WRITE |
v | READ
+
Convert to UTC Convert from UTC to config.time_zone
+ ^
| |
WRITE | READ
| |
v +
+--------------------------------+
| |
| DB |
| |
| UTC |
+--------------------------------+
Hope this helps.