# Name this method

**URL:** <https://www.ruby-forum.com/t/name-this-method/121920>\
**Category:** Ruby\
**Created:** [December 2, 2007, 9:58pm UTC](https://www.ruby-forum.com/t/name-this-method/121920 "2007-12-02T21:58:33Z")\
**Posts on this page:** 7\
**Page:** 1

<div class="post-metadata">

**Author:** ![dewie](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/d/ac8455/32.png) [@dewie](https://www.ruby-forum.com/u/dewie)\
**Post date:** [December 2, 2007, 9:58pm UTC](https://www.ruby-forum.com/t/name-this-method/121920/1 "2007-12-02T21:58:33Z")

</div>

First off, if there’s already a method that does this please point it  
out; I couldn’t find one so I wrote my own.

It’s currently called #to\_elapsed\_time and is attached to Fixnum. What  
it does…

> > 10.to\_elapsed\_time  
> > =\> {:days=\>0, :minutes=\>0, :seconds=\>10, :hours=\>0}
> 
> > 75.to\_elapsed\_time  
> > =\> {:days=\>0, :minutes=\>1, :seconds=\>15, :hours=\>0}
> 
> > 75018.to\_elapsed\_time  
> > =\> {:days=\>0, :minutes=\>50, :seconds=\>18, :hours=\>20}
> 
> > 789010.to\_elapsed\_time  
> > =\> {:days=\>9, :minutes=\>10, :seconds=\>10, :hours=\>3}

The current name makes sense to me because I wrote it with this in mind:

started = Time.now  
ended = Time.now + some\_time\_into\_the\_future  
elapsed = (ended.to\_i - started.to\_i).to\_elapsed\_time

Looking at it now I suppose I could attach it to Time, too…

time\_1.elapsed(time\_2)

That would be kinda cool, too.

What do you think?

---

<div class="post-metadata">

**Author:** ![dewie](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/d/ac8455/32.png) [@dewie](https://www.ruby-forum.com/u/dewie)\
**Post date:** [December 2, 2007, 10:18pm UTC](https://www.ruby-forum.com/t/name-this-method/121920/2 "2007-12-02T22:18:46Z")

</div>

On Dec 2, 2007, at 3:58 PM, Daniel W. wrote:

> > > 75018.to\_elapsed\_time  
> > > =\> {:days=\>0, :minutes=\>50, :seconds=\>18, :hours=\>20}
> > 
> > > 789010.to\_elapsed\_time  
> > > =\> {:days=\>9, :minutes=\>10, :seconds=\>10, :hours=\>3}

That’s DEFINITELY a nice method to have around 🙂

Unfortunately…

> started = Time.now  
> ended = Time.now + some\_time\_into\_the\_future  
> elapsed = (ended.to\_i - started.to\_i).to\_elapsed\_time

puts ended - started  
#=\> Some Time

already works

Don’t trash your method though! It will probably come in handy one day

Ari B.  
--------------------------------------------|  
If you’re not living on the edge,  
then you’re just wasting space.

---

<div class="post-metadata">

**Author:** ![dewie](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/d/ac8455/32.png) [@dewie](https://www.ruby-forum.com/u/dewie)\
**Post date:** [December 2, 2007, 10:25pm UTC](https://www.ruby-forum.com/t/name-this-method/121920/3 "2007-12-02T22:25:44Z")

</div>

thefed wrote:

> On Dec 2, 2007, at 3:58 PM, Daniel W. wrote:
> 
> > > > 75018.to\_elapsed\_time  
> > > > =\> {:days=\>0, :minutes=\>50, :seconds=\>18, :hours=\>20}
> > > 
> > > > 789010.to\_elapsed\_time  
> > > > =\> {:days=\>9, :minutes=\>10, :seconds=\>10, :hours=\>3}
> 
> That’s DEFINITELY a nice method to have around 🙂

Thank you!

> Unfortunately…
> 
> > started = Time.now  
> > ended = Time.now + some\_time\_into\_the\_future  
> > elapsed = (ended.to\_i - started.to\_i).to\_elapsed\_time
> 
> puts ended - started  
> #=\> Some Time
> 
> already works

I aware of that, but didn’t want a float due to its inaccuracies.  
(Though I admit I’m still uncertain exactly HOW those inconsistencies  
manifest themselves, I know they can be wrong from time to time.) I  
suppose I could write…

(ended - started).to\_i

> Don’t trash your method though! It will probably come in handy one day

Thank you again! 🙂

I’ve added elapsed to Time, which piggybacks off Fixnum’s implementation  
(that sounds bad… is it?)

class Fixnum

def seconds\_into\_time  
elapsed\_time = Hash.new  
elapsed\_time[:days], remainder = self.divmod(86400)  
elapsed\_time[:hours], remainder = remainder.divmod(3600)  
elapsed\_time[:minutes], remainder = remainder.divmod(60)  
elapsed\_time[:seconds] = remainder  
elapsed\_time  
end

end

class Time

def elapsed(time)  
(time - self).to\_i.seconds\_into\_time  
end

end

As you can see I renamed it to #seconds\_into\_time. Any thoughts on that  
name?

I like the to\_xxx family of methods, but…

100.to\_time\_breakdown  
100.from\_seconds\_into\_time\_breakdown  
100.to\_time  
100.to\_elapsed\_time

None of them feel right. I’m sad. =(

---

<div class="post-metadata">

**Author:** ![dewie](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/d/ac8455/32.png) [@dewie](https://www.ruby-forum.com/u/dewie)\
**Post date:** [December 2, 2007, 10:31pm UTC](https://www.ruby-forum.com/t/name-this-method/121920/4 "2007-12-02T22:31:04Z")

</div>

On Dec 2, 1:58 pm, Daniel W. [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) wrote:

> =\> {:days=\>0, :minutes=\>1, :seconds=\>15, :hours=\>0}\>\> 75018.to\_elapsed\_time
> 
> Looking at it now I suppose I could attach it to Time, too…
> 
> time\_1.elapsed(time\_2)
> 
> That would be kinda cool, too.
> 
> ## What do you think?
> 
> Posted viahttp://www.ruby-forum.com/.

You might want to take a look at the Duration gem:  
[http://rubyforge.org/projects/duration/](http://rubyforge.org/projects/duration/)

It’s very similar to what you have here.

HTH,  
Chris

---

<div class="post-metadata">

**Author:** ![dewie](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/d/ac8455/32.png) [@dewie](https://www.ruby-forum.com/u/dewie)\
**Post date:** [December 2, 2007, 10:41pm UTC](https://www.ruby-forum.com/t/name-this-method/121920/5 "2007-12-02T22:41:28Z")

</div>

Chris S. wrote:

> You might want to take a look at the Duration gem:  
> [http://rubyforge.org/projects/duration/](http://rubyforge.org/projects/duration/)
> 
> It’s very similar to what you have here.

Damn it! That makes so much more sense! Just like Ruby makes the concept  
of a range explicit via Range, I should have thought to make _duration_  
(brilliant name, by the way) explicit via Duration.

Objects, Daniel, objects! Not objects grafted as methods onto other  
objects!

Here’s an excerpt from the doc:

require ‘duration’  
=\> true  
d = Duration.new(60 \* 60 \* 24 \* 10 + 120 + 30)  
=\> #\<Duration: 1 week, 3 days, 2 minutes and 30 seconds\>  
d.to\_s  
=\> “1 week, 3 days, 2 minutes and 30 seconds”  
[d.weeks, d.days]  
=\> [1, 3]  
d.days = 7; d  
=\> #\<Duration: 2 weeks, 2 minutes and 30 seconds\>  
d.strftime(‘%w w, %d d, %h h, %m m, %s s’)  
=\> “2 w, 0 d, 0 h, 2 m, 30 s”

And a direct link to the docs:  
[http://duration.rubyforge.org/doc/](http://duration.rubyforge.org/doc/)

Thanks Chris for pointing this out to me.

---

<div class="post-metadata">

**Author:** ![dewie](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/d/ac8455/32.png) [@dewie](https://www.ruby-forum.com/u/dewie)\
**Post date:** [December 3, 2007, 4:50am UTC](https://www.ruby-forum.com/t/name-this-method/121920/6 "2007-12-03T04:50:36Z")

</div>

On Dec 2, 1:58 pm, Daniel W. [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) wrote:

> =\> {:days=\>0, :minutes=\>1, :seconds=\>15, :hours=\>0}\>\> 75018.to\_elapsed\_time
> 
> =\> {:days=\>0, :minutes=\>50, :seconds=\>18, :hours=\>20}\>\> 789010.to\_elapsed\_time
> 
> =\> {:days=\>9, :minutes=\>10, :seconds=\>10, :hours=\>3}
> 
> The current name makes sense to me because I wrote it with this in mind:
> 
> started = Time.now  
> ended = Time.now + some\_time\_into\_the\_future  
> elapsed = (ended.to\_i - started.to\_i).to\_elapsed\_time

Not as cool as the duration gem, but I offer this also:  
[http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-talk/266462](http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-talk/266462)

---

<div class="post-metadata">

**Author:** ![dewie](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/d/ac8455/32.png) [@dewie](https://www.ruby-forum.com/u/dewie)\
**Post date:** [December 3, 2007, 5:13am UTC](https://www.ruby-forum.com/t/name-this-method/121920/7 "2007-12-03T05:13:58Z")

</div>

Phrogz wrote:

> On Dec 2, 1:58 pm, Daniel W. [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) wrote:
> 
> > started = Time.now  
> > ended = Time.now + some\_time\_into\_the\_future  
> > elapsed = (ended.to\_i - started.to\_i).to\_elapsed\_time
> 
> Not as cool as the duration gem, but I offer this also:  
> [http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-talk/266462](http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-talk/266462)

That approach works for a while but you can’t accurately represent  
months or years because some months and some years have more seconds in  
them than some others. Let’s see if I can get anyone interested in my  
implementation…

require "date  
class Time

#get the difference between 2 times as number of  
years+months+days+…  
def diff(other)  
t1,t2 = [self,other].map do |t|  
DateTime.new(t.year, t.mon, t.day, t.hour, t.min, t.sec,  
Rational(t.utc\_offset, 86400))  
end  
diff = Hash.new(0)  
diff[:past] = t2 \< t1  
t1,t2 = t2,t1 if diff[:past]  
t = t1  
diff[:str] = “”  
t = calc\_diff(diff,:year, t2){ |n| t \>\> 12_n }  
t = calc\_diff(diff,:month, t2){ |n| t \>\> n }  
t = calc\_diff(diff,:day, t2){ |n| t + n }  
t = calc\_diff(diff,:hour, t2){ |n| t + Rational(n,24) }  
t = calc\_diff(diff,:minute,t2){ |n| t + Rational(n,24_60) }  
t = calc\_diff(diff,:second,t2){ |n| t + Rational(n,24_60_60) }  
diff  
end

#utility method used above  
def calc\_diff(diff,type,t2)  
diff[type] += 1 until t2 \< yield(diff[type]+1)  
if diff[type] \> 0  
diff[:str] \<\< ", " unless diff[:str].empty?  
diff[:str] \<\< “#{diff[type]} #{type}”  
diff[:str] \<\< “s” if diff[type] \> 1  
end  
yield(diff[type])  
end  
private :calc\_diff

#get the difference between 2 times as a human-friendly string  
#e.g. “5 hours, 23 minutes”  
def span\_to(other)  
n = other - self  
return “%.3f second” % n if n.abs \< 1  
d = self.diff(other)  
str = d[:str].split(“,”).first(2).join(“,”)  
str.gsub!(/(\d+)/,‘-\1’) if d[:past]  
return str  
end

def time\_past  
self.span\_to(Time.now)  
end

def time\_left  
Time.now.span\_to(self)  
end

end

> > t = Time.now  
> > =\> Mon Dec 03 13:02:21 JST 2007

> > t.diff(t+3600)  
> > =\> {:hour=\>1, :str=\>“1 hour”, :past=\>false}

> > t.diff(t+86400)  
> > =\> {:str=\>“1 day”, :day=\>1, :past=\>false}

> > t.diff(t+123456)  
> > =\> {:second=\>36, :hour=\>10, :str=\>“1 day, 10 hours, 17 minutes, 36  
> > seconds”, :day=\>1, :past=\>false, :minute=\>17}

> > Time.mktime(2007,1,1).diff Time.mktime(2007,10,1)  
> > =\> {:str=\>“9 months”, :past=\>false, :month=\>9}

> > Time.mktime(2007,1,1).diff Time.mktime(2008,1,1)  
> > =\> {:year=\>1, :str=\>“1 year”, :past=\>false}
