Skip to content

Commit

Permalink
Add support for weeks
Browse files Browse the repository at this point in the history
  • Loading branch information
Lauran Jansen committed Feb 18, 2016
1 parent 92750b6 commit e13195e
Show file tree
Hide file tree
Showing 2 changed files with 65 additions and 37 deletions.
37 changes: 29 additions & 8 deletions lib/dotiw/time_hash.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

module DOTIW
class TimeHash
TIME_FRACTIONS = [:seconds, :minutes, :hours, :days, :months, :years]
TIME_FRACTIONS = [:seconds, :minutes, :hours, :days, :weeks, :months, :years]

attr_accessor :distance, :smallest, :largest, :from_time, :to_time

Expand Down Expand Up @@ -48,10 +48,12 @@ def build_time_hash
build_minutes
elsif distance < 1.day
build_hours
elsif distance < 28.days
elsif distance < 7.days
build_days
else # greater than a month
build_years_months_days
elsif distance < 28.days
build_weeks
else # greater than a week
build_years_months_weeks_days
end
end
end
Expand All @@ -76,28 +78,46 @@ def build_days
output[:days], self.distance = distance.divmod(1.day) if output[:days].nil?
end

def build_weeks
output[:weeks], self.distance = distance.divmod(1.week) if output[:weeks].nil?
end

def build_months
build_years_months_days
build_years_months_weeks_days

if (years = output.delete(:years)) > 0
output[:months] += (years * 12)
end
end

def build_years_months_days
def build_years_months_weeks_days
months = (largest.year - smallest.year) * 12 + (largest.month - smallest.month)
years, months = months.divmod(12)

days = largest.day - smallest.day

weeks, days = days.divmod(7)

# Will otherwise incorrectly say one more day if our range goes over a day.
days -= 1 if largest.hour < smallest.hour

if days < 0
# Convert the last month to days and add to total
# Convert a week to days and add to total
weeks -= 1
days += 7
end

if weeks < 0
# Convert the last month to a week and add to total
months -= 1
last_month = largest.advance(:months => -1)
days += Time.days_in_month(last_month.month, last_month.year)
days_in_month = Time.days_in_month(last_month.month, last_month.year)
weeks += days_in_month / 7
days += days_in_month % 7
if days >= 7
days -= 7
weeks += 1
end
end

if months < 0
Expand All @@ -108,6 +128,7 @@ def build_years_months_days

output[:years] = years
output[:months] = months
output[:weeks] = weeks
output[:days] = days

total_days, self.distance = distance.abs.divmod(1.day)
Expand Down
65 changes: 36 additions & 29 deletions spec/lib/dotiw_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,9 @@
[10.minutes.to_i, "10 minutes"],
[1.hour.to_i, "1 hour"],
[1.hour + 30.seconds, "1 hour and 30 seconds"],
[4.weeks.to_i, "28 days"],
[24.weeks.to_i, "5 months and 15 days"]
[4.weeks.to_i, "4 weeks"],
[4.weeks + 2.days, "4 weeks and 2 days"],
[24.weeks.to_i, "5 months, 2 weeks, and 1 day"]
]
fragments.each do |number, result|
it "#{number} == #{result}" do
Expand All @@ -38,7 +39,7 @@
expect(distance_of_time(2.5.hours + 30.seconds, except: 'seconds')).to eq("2 hours and 30 minutes")
end

it "except:seconds har higher presedence than include_seconds:true" do
it "except:seconds has higher precedence than include_seconds:true" do
expect(distance_of_time(1.2.minute, include_seconds: true, except: 'seconds')).to eq('1 minute')
end
end
Expand All @@ -48,7 +49,7 @@
describe "hash version" do
describe "giving correct numbers of" do

[:years, :months, :days, :minutes, :seconds].each do |name|
[:years, :months, :weeks, :days, :minutes, :seconds].each do |name|
describe name do
it "exactly" do
hash = distance_of_time_in_words_hash(START_TIME, START_TIME + 1.send(name))
Expand All @@ -64,13 +65,14 @@

it "should be happy with lots of measurements" do
hash = distance_of_time_in_words_hash(START_TIME,
START_TIME + 1.year + 2.months + 3.days + 4.hours + 5.minutes + 6.seconds)
START_TIME + 1.year + 2.months + 3.weeks + 4.days + 5.hours + 6.minutes + 7.seconds)
expect(hash[:years]).to eq(1)
expect(hash[:months]).to eq(2)
expect(hash[:days]).to eq(3)
expect(hash[:hours]).to eq(4)
expect(hash[:minutes]).to eq(5)
expect(hash[:seconds]).to eq(6)
expect(hash[:weeks]).to eq(3)
expect(hash[:days]).to eq(4)
expect(hash[:hours]).to eq(5)
expect(hash[:minutes]).to eq(6)
expect(hash[:seconds]).to eq(7)
end
end
end
Expand All @@ -91,14 +93,14 @@
[START_TIME, START_TIME + 1.minute, "1 minute"],
[START_TIME, START_TIME + 3.years, "3 years"],
[START_TIME, START_TIME + 10.years, "10 years"],
[START_TIME, START_TIME + 10.years, "10 years"],
[START_TIME, START_TIME + 8.months, "8 months"],
[START_TIME, START_TIME + 3.hour, "3 hours"],
[START_TIME, START_TIME + 13.months, "1 year and 1 month"],
# Any numeric sequence is merely coincidental.
[START_TIME, START_TIME + 1.year + 2.months + 3.days + 4.hours + 5.minutes + 6.seconds, "1 year, 2 months, 3 days, 4 hours, 5 minutes, and 6 seconds"],
[START_TIME, START_TIME + 1.year + 2.months + 3.weeks + 4.days + 5.hours + 6.minutes + 7.seconds, "1 year, 2 months, 3 weeks, 4 days, 5 hours, 6 minutes, and 7 seconds"],
["2009-3-16".to_time, "2008-4-14".to_time, "11 months and 2 days"],
["2009-3-16".to_time + 1.minute, "2008-4-14".to_time, "11 months, 2 days, and 1 minute"],
["2009-4-14".to_time, "2008-3-16".to_time, "1 year and 29 days"],
["2009-4-14".to_time, "2008-3-16".to_time, "1 year, 4 weeks, and 1 day"],
["2009-2-01".to_time, "2009-3-01".to_time, "1 month"],
["2008-2-01".to_time, "2008-3-01".to_time, "1 month"]
]
Expand Down Expand Up @@ -126,10 +128,14 @@
START_TIME + 2.day + 10000.hour + 10.second,
:days,
"418 days, 16 hours, and 10 seconds"],
[START_TIME,
START_TIME + 2.day + 10000.hour + 10.second,
:weeks,
"59 weeks, 5 days, 16 hours, and 10 seconds"],
[START_TIME,
START_TIME + 2.day + 10000.hour + 10.second,
:months,
"13 months, 22 days, 16 hours, and 10 seconds"],
"13 months, 3 weeks, 1 day, 16 hours, and 10 seconds"],
["2015-1-15".to_time, "2016-3-15".to_time, :months, "14 months"]

]
Expand All @@ -148,8 +154,9 @@
[5.minutes.to_i, "5 minutes"],
[10.minutes.to_i, "10 minutes"],
[1.hour.to_i, "1 hour"],
[4.weeks.to_i, "28 days"],
[24.weeks.to_i, "5 months and 15 days"]
[6.days.to_i, "6 days"],
[4.weeks.to_i, "4 weeks"],
[24.weeks.to_i, "5 months, 2 weeks, and 1 day"]
]
fragments.each do |start, output|
it "should be #{output}" do
Expand All @@ -164,9 +171,9 @@
fragments = [
# Any numeric sequence is merely coincidental.
[START_TIME,
START_TIME + 1.year + 2.months + 3.days + 4.hours + 5.minutes + 6.seconds,
START_TIME + 1.year + 2.months + 3.weeks + 4.days + 5.hours + 6.minutes + 7.seconds,
{ :words_connector => " - " },
"1 year - 2 months - 3 days - 4 hours - 5 minutes, and 6 seconds"],
"1 year - 2 months - 3 weeks - 4 days - 5 hours - 6 minutes, and 7 seconds"],
[START_TIME,
START_TIME + 5.minutes + 6.seconds,
{ :two_words_connector => " - " },
Expand All @@ -191,25 +198,25 @@
{ :only => ["minutes", "hours"]},
"1 hour and 1 minute"],
[START_TIME,
START_TIME + 1.year + 2.months + 3.days + 4.hours + 5.minutes + 6.seconds,
START_TIME + 1.year + 2.months + 3.weeks + 4.days + 5.hours + 6.minutes + 7.seconds,
{ :vague => true },
"about 1 year"],
[START_TIME,
START_TIME + 1.year + 2.months + 3.days + 4.hours + 5.minutes + 6.seconds,
START_TIME + 1.year + 2.months + 3.weeks + 4.days + 5.hours + 6.minutes + 7.seconds,
{ :vague => "Yes please" },
"about 1 year"],
[START_TIME,
START_TIME + 1.year + 2.months + 3.days + 4.hours + 5.minutes + 6.seconds,
START_TIME + 1.year + 2.months + 3.weeks + 4.days + 5.hours + 6.minutes + 7.seconds,
{ :vague => false },
"1 year, 2 months, 3 days, 4 hours, 5 minutes, and 6 seconds"],
"1 year, 2 months, 3 weeks, 4 days, 5 hours, 6 minutes, and 7 seconds"],
[START_TIME,
START_TIME + 1.year + 2.months + 3.days + 4.hours + 5.minutes + 6.seconds,
START_TIME + 1.year + 2.months + 3.weeks + 4.days + 5.hours + 6.minutes + 7.seconds,
{ :vague => nil },
"1 year, 2 months, 3 days, 4 hours, 5 minutes, and 6 seconds"],
"1 year, 2 months, 3 weeks, 4 days, 5 hours, 6 minutes, and 7 seconds"],
[START_TIME,
START_TIME + 1.year + 2.months + 3.days + 4.hours + 5.minutes + 6.seconds,
START_TIME + 1.year + 2.months + 3.weeks + 4.days + 5.hours + 6.minutes + 7.seconds,
{ :except => "minutes" },
"1 year, 2 months, 3 days, 4 hours, and 6 seconds"],
"1 year, 2 months, 3 weeks, 4 days, 5 hours, and 7 seconds"],
[START_TIME,
START_TIME + 1.hour + 2.minutes + 3.seconds,
{ :highest_measure_only => true },
Expand All @@ -225,15 +232,15 @@
[START_TIME,
START_TIME + 2.year + 3.weeks + 4.days + 5.hours + 6.minutes + 7.seconds,
{ :highest_measures => 2 },
"2 years and 25 days"],
"2 years and 3 weeks"],
[START_TIME,
START_TIME + 4.days + 6.minutes + 7.seconds,
{ :highest_measures => 3 },
"4 days, 6 minutes, and 7 seconds"],
[START_TIME,
START_TIME + 1.year + 2.weeks,
{ :highest_measures => 3 },
"1 year and 14 days"],
"1 year and 2 weeks"],
[START_TIME,
START_TIME + 1.days,
{ :only => [:years, :months] },
Expand All @@ -260,8 +267,8 @@

it "removes seconds in all other cases" do
expect(distance_of_time_in_words(START_TIME,
START_TIME + 1.year + 2.months + 3.days + 4.hours + 5.minutes + 6.seconds,
false)).to eq("1 year, 2 months, 3 days, 4 hours, and 5 minutes")
START_TIME + 1.year + 2.months + 3.weeks + 4.days + 5.hours + 6.minutes + 7.seconds,
false)).to eq("1 year, 2 months, 3 weeks, 4 days, 5 hours, and 6 minutes")
end
end # include_seconds
end
Expand Down

0 comments on commit e13195e

Please sign in to comment.