Recently, I get a chance to look deeper in Time zone concept. Actually, The site I was working have its target audience in USA, but the server is located in India. QA guys have reported that, the login time or any other time based data is not having actual value of the time the user accessing the site from USA. A Ticket is raised to fix the issue. There exact requirement is to fix the time to USA pacific time.
Rails provide a very easy way to do this. But the main problem is to we aware of the correct use of Time class in your code. I will go step by step
STEP 1: knowing different time zone supported by rails.
TimeZone is part of active support provided by rails. You can get more detail on it here . You can find all the detail about zone by running below rake command on your project root.
listing all the time zone.
$ rake time:zones:all * UTC -07:00 * Mountain Time (US & Canada) * UTC -06:00 * Central America Central Time (US & Canada) * UTC -05:00 * Bogota Eastern Time (US & Canada) Indiana (East) * UTC -02:00 * Mid-Atlantic * UTC +01:00 * Amsterdam Belgrade * UTC +02:00 * Athens Bucharest Cairo * UTC +03:00 * Baghdad Kuwait * UTC +05:00 * Islamabad Karachi Tashkent * UTC +05:30 * Chennai Kolkata Mumbai New Delhi * UTC +05:45 * Kathmandu * UTC +10:00 * Brisbane Canberra * UTC +11:00 * New Caledonia Vladivostok * UTC +12:00 * Auckland Fiji
It will give you all the available time zone. You can filter the result by giving hour offset from GMT. In the above listing +12.00 mean the UTC(Universal Time Coordinated) time is 12 hour ahead of GMT(Greenwich Mean Time).
$ rake time:zones:all OFFSET=+12 * UTC +12:00 * Auckland Fiji Kamchatka Magadan Marshall Is. Solomon Is. Wellington
So you can see that it has listed only those time zone which is 12 hour ahed of GMT
There is also rake task to get time zones within USA
$ rake time:zones:us * UTC -10:00 * Hawaii * UTC -09:00 * Alaska * UTC -08:00 * Pacific Time (US & Canada) * UTC -07:00 * Arizona Mountain Time (US & Canada) * UTC -06:00 * Central Time (US & Canada) * UTC -05:00 * Eastern Time (US & Canada) Indiana (East)
You can also find loacl time zone i,e time zones within the country your computer is located.
$ rake time:zones:local * UTC +05:30 * Chennai Kolkata Mumbai New Delhi
O.K..so we know have list of all the available time zone, in next step we will configure rails to use the zone we specify.
STEP 2: setting time zone
By default rails assume time zone to be GMT. you can find it by going to your rails console
1.9.3p194 :001 > Time.zone => (GMT+00:00) UTC
O.k let us set it to Pacific Time (US & Canada). It can be set in config/application.rb file, there you can find below lines, suggesting how to set time zone
# Set Time.zone default to the specified zone and make Active Record auto-convert to this zone. # Run "rake -D time" for a list of tasks for finding time zone names. Default is UTC. # config.time_zone = 'Central Time (US & Canada)'
So just uncomment the last line and put your required time zone
config.time_zone = "Pacific Time (US & Canada)"
Now restart your rails console and check the time zone again
1.9.3p194 :001 > Time.zone => (GMT-08:00) Pacific Time (US & Canada)
So, now our rails loading the zone we have specified in application.rb file. In next step we will see how it affect time
STEP 3: working with Time and TimeZone
So, above we have set time zone to (GMT-08:00) Pacific Time (US & Canada) . It is 8 hour behind GMT. I’ am in india. Let us see what time is returned on the console.
1.9.3p194 :001 > Time.zone => (GMT-08:00) Pacific Time (US & Canada) 1.9.3p194 :002 > Time.now => 2013-09-09 18:28:23 +0530
But what is this…zone is showing properly, but time is still the time my computer is showing.
This is because, Time and DateTime are ruby classes, they know nothing about rails. ruby Time object derive its time from the machine on which it is working, so If your machine or server is in India, it will show current time of India, if in Australia , it will show current time of Australia and so on. So we can summarize the problem as “Rails Time not inheriting from application.rb configuration” .
The solution here is to use zone method provided by TimeZone class . zone method will basically, wrap the timeobject in the TimeZone provided in the setting. So you should use Time.zone.now instead of Time.now
NOTE : make it a practice to use Time.zone.now instead of Time.now
1.9.3p194 :001 > Time.zone.now => Mon, 09 Sep 2013 07:20:41 PDT -07:00
So now it is giving correct time based on configured time zone. I was using Time.now in around 20 files and have to change them to Time.zone.now. So, made it as a practice to use Time.zone.now instead of Time.now to retrieve the current time.
You can also, override setting in application.rb at anywhere in your code by Time.zone= method
1.9.3p194 :009 > Time.zone = "Kuwait" # it will set time zone to kuwait => "Kuwait" 1.9.3p194 :010 > Time.zone.now => Mon, 09 Sep 2013 16:16:01 AST +03:00
STEP 4: converting Time between different TimeZone
The above steps tell you how to configure your application to render time as per a perticuler timeZone you want. But what If, your application work with third Party Services and API which retrun date as string in some other time zone. Say, one of the API Iam working return “2013-11-13T23:26:13.655-08:00” as the date of uploaded pic.
Since here, we do not get a Time object, we should first convert it into a Time object. You can use either to_time or parse method
1.9.3p194 :009 > time = Time.parse("2013-11-13T23:26:13.655-08:00") => 2013-11-14 12:56:13 +0530 1.9.3p194 :015 > time.strftime("%d-%b-%Y %H:%M") => "14-Nov-2013 12:56" 1.9.3p194 :011 > time="2013-11-13T23:26:13.655-08:00".to_time => 2013-11-14 07:26:13 UTC 1.9.3p194 :017 > time.strftime("%d-%b-%Y %H:%M") => "14-Nov-2013 07:26"
Now you have time object.You can see that the parse method return time as offset from UTC while the to_time method return time as per UTC. Anyway now we have time object and so now we can convert it to corrosponding time as per any timezone, by using in_time_zone method .
1.9.3p194 :019 > pacific_time = time.in_time_zone("Pacific Time (US & Canada)") => Wed, 13 Nov 2013 23:26:13 PST -08:00 1.9.3p194 :020 > pacific_time.strftime("%d-%b-%Y %H:%M") => "13-Nov-2013 23:26"
So you can see that the time as per pacific time zone is 23:26