#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_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 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 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 :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.