#31 Formatting Time
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.
/app/views/tasks/index.html.erb. This code loops through each task and displays its name. We’ll add the
due_attime 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 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.
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 Ruby 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.
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
: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.