# Representing a span of time

**URL:** <https://www.ruby-forum.com/t/representing-a-span-of-time/67655>\
**Category:** Ruby\
**Created:** [September 5, 2006, 11:02pm UTC](https://www.ruby-forum.com/t/representing-a-span-of-time/67655 "2006-09-05T23:02:08Z")\
**Posts on this page:** 4\
**Page:** 1

<div class="post-metadata">

**Author:** ![brad7a0](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/b/53a042/32.png) [@brad7a0](https://www.ruby-forum.com/u/brad7a0)\
**Post date:** [September 5, 2006, 11:02pm UTC](https://www.ruby-forum.com/t/representing-a-span-of-time/67655/1 "2006-09-05T23:02:08Z")

</div>

Say I have two time objects represented as floats like so:

x = 64299600.0  
y = 1157489583.2798

I want to subtract x from y and then represent the difference as years,  
months, days, hours, minutes and seconds.

I don’t see how the Time library would do this. Has anyone done  
something like this? If so, how?

Thanks,  
Brad

---

<div class="post-metadata">

**Author:** ![brad7a0](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/b/53a042/32.png) [@brad7a0](https://www.ruby-forum.com/u/brad7a0)\
**Post date:** [September 5, 2006, 11:28pm UTC](https://www.ruby-forum.com/t/representing-a-span-of-time/67655/2 "2006-09-05T23:28:39Z")

</div>

On Wed, 6 Sep 2006, Brad T. wrote:

> Thanks,  
> Brad

harp:~ \> cat a.rb  
class Time  
module Units  
def **less** () “/” end  
def **more** () “_" end  
def microseconds() self.send(Float( **more** ,(10 \*\* -6))) end  
def milliseconds() self.send(Float( **more** ,(10 \*\* -3))) end  
def seconds() self end  
def minutes() seconds.send( **more** ,60) end  
def hours() minutes.send( **more** ,60) end  
def days() hours.send( **more** ,24) end  
def weeks() days.send( **more** ,7) end  
def months() weeks.send( **more** ,4) end  
def years() months.send( **more** ,12) end  
def decades() years.send( **more** ,10) end  
def centuries() decades.send( **more** ,10) end  
instance\_methods.select{|m| m !~ /\_\_/}.each do |plural|  
singular = plural.chop  
alias\_method singular, plural  
end  
end  
module DiffUnits  
include ::Time::Units  
def **less** () "_” end  
def **more** () “/” end  
end  
alias\_method “ **delta** ”, “-” unless respond\_to? “ **delta** ”  
def - other  
ret = **delta** other  
ret.extend DiffUnits  
ret  
end  
end  
class Numeric  
include ::Time::Units  
end

if $0 == **FILE**  
require “yaml”  
require “time”

now = Time::now

a = now  
y ‘a’ =\> a

b = now + 2.hours + 2.minutes  
y ‘b’ =\> b

d = b - a  
%w( seconds minutes hours days ).each do |unit|  
y “d.#{ unit }” =\> d.send(unit)  
end  
end

harp:~ \> ruby a.rb  
a: 2006-09-05 15:26:06.341147 -06:00  
b: 2006-09-05 17:28:06.341147 -06:00  
d.seconds: 7320.0  
d.minutes: 122.0  
d.hours: 2.03333333333333  
d.days: 0.0847222222222222

regards.

-a

---

<div class="post-metadata">

**Author:** ![brad7a0](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/b/53a042/32.png) [@brad7a0](https://www.ruby-forum.com/u/brad7a0)\
**Post date:** [September 6, 2006, 5:27am UTC](https://www.ruby-forum.com/t/representing-a-span-of-time/67655/3 "2006-09-06T05:27:09Z")

</div>

On Tue, 05 Sep 2006 15:26:41 -0600, ara.t.howard wrote:

> > I don’t see how the Time library would do this. Has anyone done  
> > something like this? If so, how?

[SNIP-CODE]

> harp:~ \> ruby a.rb  
> a: 2006-09-05 15:26:06.341147 -06:00  
> b: 2006-09-05 17:28:06.341147 -06:00  
> d.seconds: 7320.0  
> d.minutes: 122.0  
> d.hours: 2.03333333333333  
> d.days: 0.0847222222222222

I think he wants something more like this, where all of the different  
options collectively add up to the total time interval (rather than  
yours  
where each different unit of time nonetheless represents the whole span)

class TimeSpan

# takes input in seconds because that’s what Time#to\_i returns

def initialize(seconds)  
@raw\_seconds=seconds  
breakdown  
end

attr\_reader :seconds,:minutes,:hours,:days  
attr\_reader :raw\_seconds

private  
attr\_writer :seconds,:minutes,:hours,:days

# [:x=,y] represents that y is the maximum number of x before

# carrying over to the next larger unit of time

FACTORS=[[:seconds=,60],[:minutes=,60],  
[:hours=,24],[:days=,nil]]

def breakdown  
higherintervals=@raw\_seconds  
FACTORS.each do |method, max|  
higherintervals, thisinterval=   
higherintervals.divmod(max) unless max==nil  
thisinterval=higherintervals if max==nil  
send(method,thisinterval)  
end  
end  
end

irb(main):020:0\> a=Time.now.to\_i  
=\> 1157512271  
irb(main):021:0\> b=Time.now.to\_i  
=\> 1157512296  
irb(main):025:0\> TimeSpan.new(b-a)  
=\> #\<TimeSpan:0xa7cbfc58 @days=0, @hours=0, @minutes=0,  
@seconds=25, @raw\_seconds=25\>

Can’t do years and months without more complicated math, and a definite  
knowledge of what the start date and end date are. But at least this  
should be closer.

–Ken B.

---

<div class="post-metadata">

**Author:** ![brad7a0](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/b/53a042/32.png) [@brad7a0](https://www.ruby-forum.com/u/brad7a0)\
**Post date:** [September 6, 2006, 11:05am UTC](https://www.ruby-forum.com/t/representing-a-span-of-time/67655/4 "2006-09-06T11:05:35Z")

</div>

Brad T. wrote:

> Say I have two time objects represented as floats like so:
> 
> x = 64299600.0  
> y = 1157489583.2798
> 
> I want to subtract x from y and then represent the difference as years,  
> months, days, hours, minutes and seconds.
> 
> I don’t see how the Time library would do this. Has anyone done  
> something like this? If so, how?

This may not be exactly what you had in mind, but it’s better than the  
other  
proposed “solutions” when it comes to displaying the number of months or  
years  
between two dates: (uses rails activesupport)

class Time  
def time\_span(other = nil)  
other ||= self.utc? ? Time.now.utc : Time.now  
other.time\_spent(self)  
end  
def time\_spent(other = nil)  
other ||= self.utc? ? Time.now.utc : Time.now  
n = other - self  
case n.abs  
when 0…60 #1.minute  
“%d seconds” % n  
when 0…3600 #1.hour  
“%.1f minutes” % (n / 60)  
when 0…86400 #1.day  
“%.1f hours” % (n / 3600)  
else  
sign = “-” if self \> other  
t1,t2 = [other,self].sort  
if t2.year != t1.year and t2 \>= t1.advance(:years=\>1)  
nb\_years = t2.year - t1.year  
t = t1.advance(:years =\> nb\_years)  
t = t1.advance(:years =\> (nb\_years -= 1)) if t \> t2  
“#{sign}%.1f years” % (nb\_years + (t2 - t).to\_f /  
(t.advance(:years=\>1)

- t))  
elsif t2 \>= t1.advance(:months=\>1)  
nb\_months = (t1.year==t2.year ? 0 : 12) + t2.month - t1.month  
t = t1.advance(:months =\> nb\_months)  
t = t1.advance(:months =\> (nb\_months -= 1)) if t \> t2  
“#{sign}%.1f months” % (nb\_months + (t2 - t).to\_f /  
(t.advance(:months=\>1) - t))  
else  
“%.1f days” % (n / 1.0.day)  
end  
end  
end  
end

> > t.time\_span(t - 26.seconds)  
> > =\> “26 seconds”
> 
> > t.time\_span(t - 26.hours)  
> > =\> “1.1 days”
> 
> > t.time\_span(t - 26.days)  
> > =\> “26.0 days”
> 
> > t.time\_span(t - 26.months)  
> > =\> “2.1 years”
