Suppose we have a Rails application and we are using Postgresql as a database. There is always a question of what is the best way to deal with the time zones in this situation. In most cases that won't be of any importance, but if you have users from around the world and they need to know the exact point in time when something happened (banking transactions), then it is extremely important that you have time zones properly set in the application and on the server.

Prerequisite

Let's start with a simple create script that we want to execute on the database server (you could use migrations in Rails, but I want to have a full control over the database so I like it this way):

Here we have two columns of type TIMESTAMP, you should always put your timestamp columns to be WITH TIME ZONE, there's no need to store time without time zone because you won't gain anything with it, but you could lose a lot even you don't need time zones. After you execute this script, you should create a model in your Rails application according to the table (testing.rb). Now let's begin to play with it.

Timezone on postgresql server

I suppose that you already installed your Postgresql server. If so, first you should check which time zone is set on the server with this command:

showtimezone;

If the server isn't set to UTC time zone, you should do that by going to the file postgresql.conf. Locate timezone variable and change it to UTC (timezone = 'UTC'). Save the file, restart your server and check again with that command that the time zone is properly changed. By the way, this file is located under the path '\PostgreSQL\9.4\data' (if you have 9.4 version installed).

If, for some reason, you wish to configure different time zone on your server, be sure to set that same time zone inside your Rails application.

Timezone in rails application

In your Rails application, if you open file 'config/application.rb', you could see that the default time zone for the application is set to UTC, and you should leave it that way. But if you set different time zone on your Postgresql server, than you should set that same time zone in here. You can use this command to see which time zones are available in Rails:

$ rake time:zones:all

And this you can use to see the time zone which is set on your system, not in the application:

$ rake time:zones:local

Handling timezones

If you start your Rails console and type this:

$ test1 = Testing.create(name: 'Test1')

In your database you will create a data which will have for TESTING_TIME_1_AT current time in the UTC format, because previously you set your database to UTC and also you specified default value for this column. And if you do this:

You will change time zone in your Rails application so TESTING_TIME_2_AT will be set to time you entered but converted into UTC, because of the database, therefore '2015-03-13 13:00:00+00' if you do SELECT on the table.

Before we continue, one thing is important to notice. When one specific event occurs, time of that event is absolute, not relative, it's exactly one point in time. So if you have that point in time you can convert that time across different time zones. That's why it is important to store time zones in your database. If you don't do that, you won't have correct data when that event occurred because without time zone specified, that event might occur anytime during that day. If you have time in your database set to '2015-03-13 2pm' for example, you won't know what is the absolute time of that event regardless that hour of the day is entered. You won't know if that is London's time or Moscow's time...

You should try now to execute commands Time.now and Time.zone.now and you'll probably find yourself even more wondering what the hell is happening here. This is the explanation:

Time.now - gives you the time in system time zone, this is provided by Ruby and it doesn't know anything about our timezone configuration we just set.Time.zone.now - is provided by Rails and gives you Time.zone value that we set in Rails.

You might be surprised that inside your database you will get the same time for TESTING_TIME_2_AT in these two cases, not different one like you might think. This is fun, isn't it :) The catch here is that we set UTC time inside of the database and there is only one correct time IN THIS CURRENT MOMENT, not two, regardless which NOW method you use.

Now when you select your data from the database, you'll get '2015-03-15 06:00:00+00' for TESTING_TIME_2_AT. That means that you inserted data with time zone from Honolulu and Postgresql converted it into UTC time which is 10 hours behind the UTC time zone. So when it's 8 pm in Honolulu on 14th of March, in London it will be 6 am on 15th of March, so we got everything right, we have exactly one point in time correctly inserted into our database.

Let's try something more here:

test6.testing_time_2_at = 'Sat, 14 Mar 2015 20:00:00 HST -10:00' - this gives time in time zone which is set in the Rails application.test6.testing_time_2_at.localtime = '2015-03-15 07:00:00 +0100' - this gives time in local time zone, I am in Belgrade.test6.testing_time_2_at.in_time_zone("Eastern Time (US & Canada)") = 'Sun, 15 Mar 2015 02:00:00 EDT -04:00' - you can convert time from database into any time zone you wish.

Wrap up

1) If you need to know a point in time when some event occurred then it isn't relevant what type of time zone you forward to the database because the database is set to the UTC time zone and it will always store time in UTC format, therefore you will have infallible data about time. The example is when you create a record in the database and time zone isn't important to the user of your application, you can forward Time.now or Time.zone.now to the database, it doesn't matter.

2) If it is important to store local time when user did some action to show it later to her, again it isn't important which time zone you forward to the database because in the database there will be set exact UTC time of that event. But when you need to show that time to the user, you need to convert it into local time for that user (for example, the time when some banking transaction occurred).

3) If user chooses a time inside of the application (for example you are building an application which sends some sort of notification to the users at the moment they defined), this is the case you need to take care of local time. Because if you don't do that, and user chooses time '2143-07-13 2pm', one day that distant year 2143 the user will receive the notification in the London timezone instead of the time that is valid in Honolulu. For this reason you need to forward to the database Time.zone.parse('2143-07-13 2pm'). It will be converted to UTC format and when you display that data to the user, you will manually convert that time into local time.

4) If you need to work on the procedures in the database, you'll always work with UTC time since every data is stored in UTC time zone, so no need to worry about converting into different time zones.

How to know the time zone of the user

One more thing you have to do to solve all problems with time zone settings is how to display that time for the user who uses your application. Since the time in your database is always in UTC format and your users can be anywhere in the world, you have to know the time zone of the person who uses your application. You can do that in two ways:

1) On the client side, using JavaScript or installing a gem that does that for you. Personally I don't like this way.

2) On the server side, take the user's location and based on that you can find the time zone. You can use gems like geocoder and timezone. Here you can have a problem if someone uses your application through a proxy, but these are borderline cases that doesn't happen often. Though if that can happen to you, in this case it is better to use client side approach with JavaScript because that data will be infallible (except if the time on that computer is incorrectly set).

Of course, you can always ask the user in a form to choose the time zone to which she belongs, so this information could be stored in the database as a user preference but that way the application loses quality because you ask a user something that you don't need to ask. This information can be obtained in a different way and thus free your user of unnecessary entries which drastically improves UX of your application.

The end

Certainly there are other ways how you can deal with time zones in your application, but I personally prefer to do it this way. However, if you work in this way or another, do not forget that the convention for working with time zones is very important when you build any application. You, as a developer, need to think of every single detail in the architecture of your system.

Hello again. It's been awhile since I wrote something but I am too busy building my startup Warrantly so I really don't have time to write often. Nevertheless, now it's time to share something new. Being a Java developer for years I switched to Ruby on Rails a year ago because we decided it could be the best tool to build a startup. Boy it was a great decision! Since then I am really enjoying exploring Ruby and Rails and I don't have any desire going back to Java again.

Don't get me wrong, Java is a great programming language but with Rails you can create a new functional website in literally minutes! And with Java you have to decide which framework to use, how to connect everything to work properly and you will spend hours figuring out that. A year and a half ago I wrote how to start a new project with Spring because it is too complicated and I wanted to write down few steps you need to do to connect everything to work properly. Now I will show you how to do the same thing with Rails and it is so damn simple you will need only 15 minutes.

PREREQUISITE

First you need to install Ruby and Rails 4 and you can find tutorials everywhere how to do that so I won't explain that part. You don't need any IDE to code your program, you can use any text editor (I prefer Sublime) and you'll need a console. Now it could be a little more complicated if you are using Windows but it won't make you some serious trouble.

CREATE NEW APP AND ADD GEMS

In your console, go to the directory you want to use to store your project and type ﻿﻿this:

CONFIGURE DATABASE

If you want to connect your project with a database then you need to configure your database.yml file located under config directory:

ZURB FOUNDATION + HAML

Since we are using ZURB and HAML now you need to go to your console again and run this line:

We are installing Foundation and overriding application layout file under view directory because we want to use HAML. Now under assets/stylesheets directory find the file application.css and rename it to application.scss. You don't need to do that but if you want to use sassy css in your whole app it is good practice to do this in this step. By the way, you are probably asking what the hell are sass and scss, are they the same thing or not? I won't explain here more on this subject but you can find great explanation about them in one railscast episode.

SIMPLE FORM

Installing simple form gem is also one liner:

ScafFold + DATABASE MIGRATION

This was really skinny tutorial but I don't want to write 5 pages long post about simple stuff. Basically the application is ready to use. You can now create model, views, migration files just using one rails command, the powerful scaffold:

In your migration file which is created with this command (under db/migrate) you can add some code, this for example:

To reflect these changes to your database you need to run three commands:

With these commands you created actual database, load you schema, populated it with some seed data (if you have any under seeds.rb file) and ran your migration file to create a database table. Find more about these commands, you will need them during your development.

THE END

I hope this can help you like my previous post about SPRING did it. If you plan to launch some startup, maybe Rails is the right tool for you.