homeASCIIcasts

31: Formatting Time 

(view original Railscast)

Other translations: It Fr

The application below shows a list of tasks. Each task has a datetime field called due_at that we’d like to be able to display next to its name.

Our list of tasks.

To do this we’ll edit the view code in /app/views/tasks/index.html.erb. This code loops through each task and displays its name. We’ll add the due_at time next to the task’s name.

<ul id="taskList">
  <% @tasks.each do |task| %>
  <li><strong><%= task.name %></strong> <%= task.due_at %></li>
  <% end %>
</ul>

The index view with the code to show the due date added.

Formatting The Dates

The dates are now shown but in the wrong format.

The due date is now shown, but the formatting is ugly; we don’t really want the date and time in that format, or time zone displayed. This is happening because due_at is a Time object and the view code is calling to_s on it to display it. We do have some choice here, though. Rails extends the to_s method to give us options for controlling the display format. We’ll try some of them with our first task and see what formats they return.

Format Result
Task.first.due_at.to_s 2009-02-19 00:00:00 UTC
Task.first.due_at.to_s(:long) February 19, 2009 00:00
Task.first.due_at.to_s(:short) 19 Feb 00:00
Task.first.due_at.to_s(:db) 2009-02-19 00:00:00

There’s a good range there, but we’re being picky and we don’t want any of them. How could we define our own custom format? Ruby’s Time object has a method called strftime that will enable us to do just that. There are many control characters for the format string, though so we’ll look at the Ruby documentation to see what’s available. We can do this by typing ri Time.strftime at the command line, or by looking at the appropriate Rails API documentation page. Either way will show us a list of format characters we can use.

Let’s try creating our own format string. We’ll update the relevant part of our view to show the due date in our own custom format.

<%= task.due_at.strftime("due on %B %d at %I:%M %p") %></li>

When we refresh our page we can see that the tasks’ due dates are now displayed as we want them.

Now our dates are displayed correctly.

The due dates now show in the correct format.

Tidying Up The Code

We’re now showing the dates in the format we want, but the view code is a little ugly and not easily reusable. We might want to use the same format in other places, so we’ll refactor a little to improve our code. There are a number of ways we could refactor the code: we could create a helper method or we could add a new method to the Task model. The route we’re going to take though is to add a new format to the to_s method. Instead of using :long, :short or :db we can create our own format and give it a name.

We’ll first change the code in our index view that displays the date in our new format.

<%= task.due_at.to_s(:due_date) %></li>

The date format needs to be loaded before the rest of the application so we’re going to add it to the environment.rb file. The various date formats are stored in a hash in the Date class called TIME_FORMATS, with the hash’s keys being strings representing the formats. All we need to do is add a new key called due_date to the hash with a value of our format string. At the bottom of environment.rb we’ll add the following line.

Time::DATE_FORMATS[:due_date] = "due on %B %d at %I:%M %p"

After we’ve added the new line and saved it we’ll have to restart our application so that the new format is picked up. If we don’t restart then the default to_s string will be displayed (and we’ll be back where we started!)

After we’ve restarted the application and gone back to the tasks index page we’ll see that our new date format is still showing and our code is much cleaner.