Display date ranges in text in Rails
Edit: This helper now comes in the form of the time_will_tell gem!
Ever wanted to display dates ranges that follow this format:
Oct 3 - 8, 2012
Jan 30 - Feb 5, 2013
Dec 26, 2012 - Jan 3, 2013
Note that the months and years only appear when appropriate. You want it? Simply add this time_helper.rb
helper in your helpers:
# encoding: utf-8
module TimeHelper
def date_range(from_date, until_date, options = {})
options.symbolize_keys!
format = options[:format] || :short
separator = options[:separator] || "—"
if format.to_sym == :short
month_names = I18n.t("date.abbr_month_names")
else
month_names = I18n.t("date.month_names")
end
from_day = from_date.day
from_month = month_names[from_date.month]
from_year = from_date.year
until_day = until_date.day
dates = { from_day: from_day }
if from_date.month == until_date.month && from_date.year == until_date.year
date_format = "same_month"
dates.merge!(until_day: until_day, month: from_month, year: from_year)
else
until_month = month_names[until_date.month]
dates.merge!(from_month: from_month, until_month: until_month, until_day: until_day)
if from_date.year == until_date.year
date_format = "different_months_same_year"
dates.merge!(year: from_year)
else
until_year = until_date.year
date_format = "different_years"
dates.merge!(from_year: from_year, until_year: until_year)
end
end
I18n.t("date_range.#{format}.#{date_format}", dates.merge(sep: separator))
end
end
And the following anywhere in your locales (I use active_support.en.yml
:
en:
date_range:
long:
different_months_same_year: "%{from_month} %{from_day} %{sep} %{until_month} %{until_day}, %{year}"
different_years: "%{from_month} %{from_day}, %{from_year} %{sep} %{until_month} %{until_day}, %{until_year}"
same_month: "%{month} %{from_day} %{sep} %{until_day}, %{year}"
short:
different_months_same_year: "%{from_month} %{from_day} %{sep} %{until_month} %{until_day}, %{year}"
different_years: "%{from_month} %{from_day}, %{from_year} %{sep} %{until_month} %{until_day}, %{until_year}"
same_month: "%{month} %{from_day} %{sep} %{until_day}, %{year}"
Then whenever you want to display a date range, just use the following:
<%= date_range(from_date, until_date) %>
Note that there are 2 options in the code above:
format
which can be either:short
or:long
(for short month names or full names)
separator
to specify the separator to use between dates
Written by Michel Billard
Related protips
6 Responses
You could probably make this a bit more readable and shorter if you called I18n.t("date_range.#{format}.#{date_format}", dates)
at the end, once, and created a dates hash with the dates before hand.
Also, you use things like from_date.day
after having already defined a variable from_day
.
Thanks @niuage, I've updated my answer with your recommendations and it does make it more readable.
Thanks for this! There's a small bug though: If your dates are Feb 10, 2014 - Feb 10, 2015, the result will be incorrect. You need to change
if from_date.month == until_date.month
to
if from_date.month == until_date.month && from_date.year == until_date.year
thanks @dopa, I've fixed the code.
Hello! Me and my colleague have wroted the gem based on your article. Thanks for your work and please look at githib: https://github.com/darkleaf/date_range_formatter
@darkleaf nice work, I've actually implemented a gem myself, just forgot to mention it here: https://github.com/mbillard/time_will_tell
It also has a helper for another thing I do with datetimes regularly which is to display distances of time but precisely (ex: "3 hours 42 minutes" instead of "3 hours ago").