mirror of
https://github.com/github/rails.git
synced 2026-01-30 08:48:06 -05:00
Improved resolution of DateHelper#distance_of_time_in_words for better precision (closes #5994) [Bob Silva]
git-svn-id: http://svn-commit.rubyonrails.org/rails/trunk@4989 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
This commit is contained in:
@@ -1,5 +1,7 @@
|
||||
*SVN*
|
||||
|
||||
* Improved resolution of DateHelper#distance_of_time_in_words for better precision #5994 [Bob Silva]
|
||||
|
||||
* Changed that uncaught exceptions raised any where in the application will cause RAILS_ROOT/public/500.html to be read and shown instead of just the static "Application error (Rails)" [DHH]
|
||||
|
||||
* Integration tests: thoroughly test ActionController::Integration::Session. #6022 [Kevin Clark]
|
||||
|
||||
@@ -13,14 +13,38 @@ module ActionView
|
||||
module DateHelper
|
||||
DEFAULT_PREFIX = 'date' unless const_defined?('DEFAULT_PREFIX')
|
||||
|
||||
# Reports the approximate distance in time between two Time objects or integers.
|
||||
# For example, if the distance is 47 minutes, it'll return
|
||||
# "about 1 hour". See the source for the complete wording list.
|
||||
# Reports the approximate distance in time between two Time or Date objects or integers as seconds.
|
||||
# Set <tt>include_seconds</tt> to true if you want more detailed approximations when distance < 1 min, 29 secs
|
||||
# Distances are reported base on the following table:
|
||||
#
|
||||
# Integers are interpreted as seconds. So,
|
||||
# <tt>distance_of_time_in_words(50)</tt> returns "less than a minute".
|
||||
# 0 <-> 29 secs # => less than a minute
|
||||
# 30 secs <-> 1 min, 29 secs # => 1 minute
|
||||
# 1 min, 30 secs <-> 44 mins, 29 secs # => [2..44] minutes
|
||||
# 44 mins, 30 secs <-> 89 mins, 29 secs # => about 1 hour
|
||||
# 89 mins, 29 secs <-> 23 hrs, 59 mins, 29 secs # => about [2..24] hours
|
||||
# 23 hrs, 59 mins, 29 secs <-> 47 hrs, 59 mins, 29 secs # => 1 day
|
||||
# 47 hrs, 59 mins, 29 secs <-> 29 days, 23 hrs, 59 mins, 29 secs # => [2..29] days
|
||||
# 29 days, 23 hrs, 59 mins, 30 secs <-> 59 days, 23 hrs, 59 mins, 29 secs # => about 1 month
|
||||
# 59 days, 23 hrs, 59 mins, 30 secs <-> 1 yr minus 31 secs # => [2..12] months
|
||||
# 1 yr minus 30 secs <-> 2 yrs minus 31 secs # => about 1 year
|
||||
# 2 yrs minus 30 secs <-> max time or date # => over [2..X] years
|
||||
#
|
||||
# Set <tt>include_seconds</tt> to true if you want more detailed approximations if distance < 1 minute
|
||||
# With include_seconds = true and the difference < 1 minute 29 seconds
|
||||
# 0-4 secs # => less than 5 seconds
|
||||
# 5-9 secs # => less than 10 seconds
|
||||
# 10-19 secs # => less than 20 seconds
|
||||
# 20-39 secs # => half a minute
|
||||
# 40-59 secs # => less than a minute
|
||||
# 60-89 secs # => 1 minute
|
||||
#
|
||||
# Examples:
|
||||
#
|
||||
# from_time = Time.now
|
||||
# distance_of_time_in_words(from_time, from_time + 50.minutes) # => about 1 hour
|
||||
# distance_of_time_in_words(from_time, from_time + 15.seconds) # => less than a minute
|
||||
# distance_of_time_in_words(from_time, from_time + 15.seconds, true) # => less than 20 seconds
|
||||
#
|
||||
# Note: Rails calculates one year as 365.25 days.
|
||||
def distance_of_time_in_words(from_time, to_time = 0, include_seconds = false)
|
||||
from_time = from_time.to_time if from_time.respond_to?(:to_time)
|
||||
to_time = to_time.to_time if to_time.respond_to?(:to_time)
|
||||
@@ -29,25 +53,25 @@ module ActionView
|
||||
|
||||
case distance_in_minutes
|
||||
when 0..1
|
||||
return (distance_in_minutes==0) ? 'less than a minute' : '1 minute' unless include_seconds
|
||||
return (distance_in_minutes == 0) ? 'less than a minute' : '1 minute' unless include_seconds
|
||||
case distance_in_seconds
|
||||
when 0..5 then 'less than 5 seconds'
|
||||
when 6..10 then 'less than 10 seconds'
|
||||
when 11..20 then 'less than 20 seconds'
|
||||
when 21..40 then 'half a minute'
|
||||
when 41..59 then 'less than a minute'
|
||||
when 0..4 then 'less than 5 seconds'
|
||||
when 5..9 then 'less than 10 seconds'
|
||||
when 10..19 then 'less than 20 seconds'
|
||||
when 20..39 then 'half a minute'
|
||||
when 40..59 then 'less than a minute'
|
||||
else '1 minute'
|
||||
end
|
||||
|
||||
when 2..45 then "#{distance_in_minutes} minutes"
|
||||
when 46..90 then 'about 1 hour'
|
||||
when 90..1440 then "about #{(distance_in_minutes.to_f / 60.0).round} hours"
|
||||
when 1441..2880 then '1 day'
|
||||
when 2881..43220 then "#{(distance_in_minutes / 1440).round} days"
|
||||
when 43201..86400 then 'about 1 month'
|
||||
when 86401..525960 then "#{(distance_in_minutes / 43200).round} months"
|
||||
when 525961..1051920 then 'about 1 year'
|
||||
else "over #{(distance_in_minutes / 525600).round} years"
|
||||
when 2..44 then "#{distance_in_minutes} minutes"
|
||||
when 45..89 then 'about 1 hour'
|
||||
when 90..1439 then "about #{(distance_in_minutes.to_f / 60.0).round} hours"
|
||||
when 1440..2879 then '1 day'
|
||||
when 2880..43199 then "#{(distance_in_minutes / 1440).round} days"
|
||||
when 43200..86399 then 'about 1 month'
|
||||
when 86400..525959 then "#{(distance_in_minutes / 43200).round} months"
|
||||
when 525960..1051919 then 'about 1 year'
|
||||
else "over #{(distance_in_minutes / 525960).round} years"
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -10,56 +10,84 @@ class DateHelperTest < Test::Unit::TestCase
|
||||
end
|
||||
|
||||
def test_distance_in_words
|
||||
from = Time.mktime(2004, 3, 6, 21, 41, 18)
|
||||
from = Time.mktime(2004, 3, 6, 21, 45, 0)
|
||||
|
||||
assert_equal "less than a minute", distance_of_time_in_words(from, Time.mktime(2004, 3, 6, 21, 41, 25))
|
||||
assert_equal "5 minutes", distance_of_time_in_words(from, Time.mktime(2004, 3, 6, 21, 46, 25))
|
||||
assert_equal "about 1 hour", distance_of_time_in_words(from, Time.mktime(2004, 3, 6, 22, 47, 25))
|
||||
assert_equal "about 3 hours", distance_of_time_in_words(from, Time.mktime(2004, 3, 7, 0, 41))
|
||||
assert_equal "about 4 hours", distance_of_time_in_words(from, Time.mktime(2004, 3, 7, 1, 20))
|
||||
assert_equal "2 days", distance_of_time_in_words(from, Time.mktime(2004, 3, 9, 15, 40))
|
||||
|
||||
# test greater date separation
|
||||
assert_equal "29 days", distance_of_time_in_words(from, Time.mktime(2004, 4, 5, 21, 41, 18))
|
||||
assert_equal "about 1 month", distance_of_time_in_words(from, Time.mktime(2004, 4, 6, 21, 41, 18))
|
||||
assert_equal "about 1 month", distance_of_time_in_words(from, Time.mktime(2004, 4, 7, 21, 41, 18))
|
||||
assert_equal "2 months", distance_of_time_in_words(from, Time.mktime(2004, 5, 6, 21, 41, 18))
|
||||
assert_equal "11 months", distance_of_time_in_words(from, Time.mktime(2005, 2, 6, 21, 41, 18))
|
||||
assert_equal "about 1 year", distance_of_time_in_words(from, Time.mktime(2005, 4, 6, 21, 41, 18))
|
||||
assert_equal "about 1 year", distance_of_time_in_words(from, Time.mktime(2005, 4, 12, 21, 41, 18))
|
||||
assert_equal "over 2 years", distance_of_time_in_words(from, Time.mktime(2006, 4, 6, 21, 41, 18))
|
||||
# 0..1 with include_seconds
|
||||
assert_equal "less than 5 seconds", distance_of_time_in_words(from, from + 0.seconds, true)
|
||||
assert_equal "less than 5 seconds", distance_of_time_in_words(from, from + 4.seconds, true)
|
||||
assert_equal "less than 10 seconds", distance_of_time_in_words(from, from + 5.seconds, true)
|
||||
assert_equal "less than 10 seconds", distance_of_time_in_words(from, from + 9.seconds, true)
|
||||
assert_equal "less than 20 seconds", distance_of_time_in_words(from, from + 10.seconds, true)
|
||||
assert_equal "less than 20 seconds", distance_of_time_in_words(from, from + 19.seconds, true)
|
||||
assert_equal "half a minute", distance_of_time_in_words(from, from + 20.seconds, true)
|
||||
assert_equal "half a minute", distance_of_time_in_words(from, from + 39.seconds, true)
|
||||
assert_equal "less than a minute", distance_of_time_in_words(from, from + 40.seconds, true)
|
||||
assert_equal "less than a minute", distance_of_time_in_words(from, from + 59.seconds, true)
|
||||
assert_equal "1 minute", distance_of_time_in_words(from, from + 60.seconds, true)
|
||||
assert_equal "1 minute", distance_of_time_in_words(from, from + 89.seconds, true)
|
||||
|
||||
# include seconds
|
||||
assert_equal "less than a minute", distance_of_time_in_words(from, Time.mktime(2004, 3, 6, 21, 41, 19), false)
|
||||
assert_equal "less than 5 seconds", distance_of_time_in_words(from, Time.mktime(2004, 3, 6, 21, 41, 19), true)
|
||||
assert_equal "less than 10 seconds", distance_of_time_in_words(from, Time.mktime(2004, 3, 6, 21, 41, 28), true)
|
||||
assert_equal "less than 20 seconds", distance_of_time_in_words(from, Time.mktime(2004, 3, 6, 21, 41, 38), true)
|
||||
assert_equal "half a minute", distance_of_time_in_words(from, Time.mktime(2004, 3, 6, 21, 41, 48), true)
|
||||
assert_equal "less than a minute", distance_of_time_in_words(from, Time.mktime(2004, 3, 6, 21, 42, 17), true)
|
||||
|
||||
assert_equal "1 minute", distance_of_time_in_words(from, Time.mktime(2004, 3, 6, 21, 42, 18), true)
|
||||
assert_equal "1 minute", distance_of_time_in_words(from, Time.mktime(2004, 3, 6, 21, 42, 28), true)
|
||||
assert_equal "2 minutes", distance_of_time_in_words(from, Time.mktime(2004, 3, 6, 21, 42, 48), true)
|
||||
# First case 0..1
|
||||
assert_equal "less than a minute", distance_of_time_in_words(from, from + 0.seconds)
|
||||
assert_equal "less than a minute", distance_of_time_in_words(from, from + 29.seconds)
|
||||
assert_equal "1 minute", distance_of_time_in_words(from, from + 30.seconds)
|
||||
assert_equal "1 minute", distance_of_time_in_words(from, from + 1.minutes + 29.seconds)
|
||||
|
||||
# 2..44
|
||||
assert_equal "2 minutes", distance_of_time_in_words(from, from + 1.minutes + 30.seconds)
|
||||
assert_equal "44 minutes", distance_of_time_in_words(from, from + 44.minutes + 29.seconds)
|
||||
|
||||
# 45..89
|
||||
assert_equal "about 1 hour", distance_of_time_in_words(from, from + 44.minutes + 30.seconds)
|
||||
assert_equal "about 1 hour", distance_of_time_in_words(from, from + 89.minutes + 29.seconds)
|
||||
|
||||
# 90..1439
|
||||
assert_equal "about 2 hours", distance_of_time_in_words(from, from + 89.minutes + 30.seconds)
|
||||
assert_equal "about 24 hours", distance_of_time_in_words(from, from + 23.hours + 59.minutes + 29.seconds)
|
||||
|
||||
# 1440..2879
|
||||
assert_equal "1 day", distance_of_time_in_words(from, from + 23.hours + 59.minutes + 30.seconds)
|
||||
assert_equal "1 day", distance_of_time_in_words(from, from + 47.hours + 59.minutes + 29.seconds)
|
||||
|
||||
# 2880..43199
|
||||
assert_equal "2 days", distance_of_time_in_words(from, from + 47.hours + 59.minutes + 30.seconds)
|
||||
assert_equal "29 days", distance_of_time_in_words(from, from + 29.days + 23.hours + 59.minutes + 29.seconds)
|
||||
|
||||
# 43200..86399
|
||||
assert_equal "about 1 month", distance_of_time_in_words(from, from + 29.days + 23.hours + 59.minutes + 30.seconds)
|
||||
assert_equal "about 1 month", distance_of_time_in_words(from, from + 59.days + 23.hours + 59.minutes + 29.seconds)
|
||||
|
||||
# 86400..525959
|
||||
assert_equal "2 months", distance_of_time_in_words(from, from + 59.days + 23.hours + 59.minutes + 30.seconds)
|
||||
assert_equal "12 months", distance_of_time_in_words(from, from + 1.years - 31.seconds)
|
||||
|
||||
# 525960..1051919
|
||||
assert_equal "about 1 year", distance_of_time_in_words(from, from + 1.years - 30.seconds)
|
||||
assert_equal "about 1 year", distance_of_time_in_words(from, from + 2.years - 31.seconds)
|
||||
|
||||
# > 1051920
|
||||
assert_equal "over 2 years", distance_of_time_in_words(from, from + 2.years - 30.seconds)
|
||||
assert_equal "over 10 years", distance_of_time_in_words(from, from + 10.years)
|
||||
|
||||
# test to < from
|
||||
assert_equal "about 4 hours", distance_of_time_in_words(Time.mktime(2004, 3, 7, 1, 20), from)
|
||||
assert_equal "less than 20 seconds", distance_of_time_in_words(Time.mktime(2004, 3, 6, 21, 41, 38), from, true)
|
||||
assert_equal "about 4 hours", distance_of_time_in_words(from + 4.hours, from)
|
||||
assert_equal "less than 20 seconds", distance_of_time_in_words(from + 19.seconds, from, true)
|
||||
|
||||
# test with integers
|
||||
assert_equal "less than a minute", distance_of_time_in_words(50)
|
||||
assert_equal "less than a minute", distance_of_time_in_words(59)
|
||||
assert_equal "about 1 hour", distance_of_time_in_words(60*60)
|
||||
|
||||
# more cumbersome test with integers
|
||||
assert_equal "less than a minute", distance_of_time_in_words(0, 50)
|
||||
assert_equal "less than a minute", distance_of_time_in_words(0, 59)
|
||||
assert_equal "about 1 hour", distance_of_time_in_words(60*60, 0)
|
||||
|
||||
end
|
||||
|
||||
def test_distance_in_words_date
|
||||
def test_distance_in_words_with_dates
|
||||
start_date = Date.new 1975, 1, 31
|
||||
end_date = Date.new 1977, 4, 17
|
||||
assert_not_equal("13 minutes",
|
||||
distance_of_time_in_words(start_date, end_date))
|
||||
end_date = Date.new 1977, 1, 31
|
||||
assert_equal("over 2 years", distance_of_time_in_words(start_date, end_date))
|
||||
end
|
||||
|
||||
def test_time_ago_in_words
|
||||
t = Time.now - 1.years
|
||||
assert_equal "about 1 year", time_ago_in_words(t)
|
||||
end
|
||||
|
||||
def test_select_day
|
||||
|
||||
Reference in New Issue
Block a user