=Ago
* by Mike Zazaian
* http://ago.rubyforge.org


== DESCRIPTION

Easy conversion of Time objects to human-readable format.


== FEATURES/PROBLEMS:

* Convert Time objects to a human-readable format.
* Convert Fixnum, Bignum, and Floats objects into Time objects


== SYNOPSIS:

=== Intro

Ago allows you to convert any Time objecto a simple, human-readable
format, like this:

t = Time.new
=> Sat Jun 20 18:09:16 +1000 2009

t.ago
=> "2 seconds ago"

You can also print out the NUMBER OF SECONDS in various units of
time, like this:

2.years
=> 63072000

3.months
=> 7776000

50.weeks
=> 30240000

And then, if you want, convert those units into Time objects:

2.years.ago
=> Thu Jun 21 18:26:59 +1000 2007

3.months.ago
=> Sun Mar 22 19:28:05 +1100 2009


=== Time to human-readable format

Ago works by calculating the difference in the number of seconds
between the given Time object and Time.now, then dividing by the
number of seconds in each unit:

* Years
* Months
* Weeks
* Days
* Hours
* Minutes
* Seconds

By default, Ago will start with the largest divisible unit, then go
down the line until all of the seconds have been accounted for.

If you, for example, had a Time object for January 1st, 1971, you
could see how many years had passed like this:

t = Time.new - 38.years - 6.months
=> Fri Jan 01 18:30:03 +1000 1971

t.ago
=> "38 years ago"

By default, Ago will show only the LARGEST UNIT in the time object.
In this case, there are 38 years in the 't' Time object, so it only
prints that number.


==== The :focus Option

If you want to access the smaller numbers, you can use the :focus
option, like this:

t.ago(:focus => :second)
=> "38 years, 6 months, 9 minutes, 8 seconds ago"

The value for focus can be either one of the units of time as a
Symbol (:year, :month, :week, :day, :hour, :minute, :second), like this:

t.ago(:focus => :month)
=> "38 years, 3 months ago"

OR, the value can be a Fixnum, which indicates how many units IN
ADDITION TO THE FIRST UNIT the Ago module will print out:

t.ago(:focus => 3)
=> "38 years, 6 months, 9 minutes, 8 seconds ago"

t.ago(:focus => 2)
=> "38 years, 6 months, 9 minutes ago"

t.ago(:focus => 0)
=> "38 years ago"

Don't worry if the number is greater than the number of possible
units in the Time object, Ago will just ignore the extra places:

t.ago(:focus => 6)
=> "4 days, 20 hours, 59 minutes, 40 seconds ago"

Make sure that number value is between 0 and 6, though, or Ago will
throw an error at you:

t.ago :focus => 3000
ArgumentError: :focus => value must either be a number between 0 and
6 (inclusive), or one of the following symbols: :year, :month, :week,
:day, :hour, :minute, and :second.
from ./ago.rb:89:in `ago'
from ./ago.rb:86:in `each'
from ./ago.rb:86:in `ago'


==== The :start_at Option

:start_at works in much the same way that the :focus option works,
but measures where the output starts rather than where it ends.

If you wanted to see how many months there were since January 1st,
1971, for example, you could do this:

t.ago(:start_at => :month)
=> "468 months ago"

or, if you wanted to see the number of days:

t.ago(:start_at => :day)
=> "14050 days ago"

And while the Symbol arguments for :start_at work similarly to those
in :focus, the numerical arguments work differently.

While the numerical arguments in :focus indicate how many ADDITIONAL
UNITS are printed, the numerical arguments for :start_at are just
codes for their Symbol counterparts, like this:

Year: 0
Month: 1
Week: 2
Day: 3
Hour: 4
Minute: 5
Second: 6

So if you want to see how many months ago January 1, 1971 occurred,
this is also a valid way to call the function:

t.ago(:start_at => 1)
=> "468 months ago"


==== Combining :focus and :start_at

Let's say you had a Time object for about 40 years ago, give or take,
and you wanted to see how many months ago it was, but also how many
weeks, days and hours. You could call it like this:

t.ago(:start_at => :month, :focus => :hour)
=> "486 months, 4 weeks, 1 day, 16 hours ago"

OR:

t.ago(:start_at => :month, :focus => 3)
=> "486 months, 4 weeks, 1 day, 16 hours ago"

OR:

t.ago(:start_at => 1, :focus => 3)
=> "486 months, 4 weeks, 1 day, 16 hours ago"


==== The :now Option

Ago automatically assumes that you want to calculate the difference
between the given Time object and NOW (Time now).

But suppose you wanted NOW to be some other point in time. Say,
three weeks ago. Then you could do this:

t = Time.now
=> Sat Jun 20 19:38:38 +1000 2009

t.ago(:now => 3.weeks.ago)
=> "2 weeks from now"

Weird that it printed "2 weeks from now" instead of three? Not
really. If you're running this in IRB, then a couple of seconds
probably passed between "t = Time.now" and "t.ago(:now => 3.weeks.ago)".

To see more precisely how long 3.weeks.ago is, you'd have to use
the :focus option:

t.ago(:now => 3.weeks.ago, :focus => :second)
=> "2 weeks, 6 days, 23 hours, 59 minutes, 56 seconds from now"

That's more like it. Note that the value for :now => can be any Time
object, even Time.now (not that you'd want to do this).


==== The :calendar Option

By default, Ago uses this BASIC calendar structure:

Year: 365 Days
Month: 30 Days
Week: 7 Days
Day: 24 Hours
Hour: 60 Minutes
Minute: 60 Seconds
Second: 1 Second

The basic calendar structure works fine when calculating small amounts
of time, because they're strong approximations for what would be
considered the average year.

When you're calculating larger amounts of time, however, you might
want a bit more accuracy. In this case you might want to use the
*GREGORIAN CALENDAR*, which uses these units of time:

Year: 365.2425 Days
Month: 30.436875 Days
Week: 7.02389423076923 Days

This might not seem like a huge difference, when calculating several
months or years it starts to add up:

t = Time.now - 60.years
=> Tue Jul 05 19:58:15 +1000 1949

t.ago :focus => :second
=> "60 years, 18 seconds ago"

t.ago :focus => :second, :calendar => :gregorian
=> "59 years, 11 months, 2 weeks, 1 day, 20 hours, 8 minutes, 20 seconds ago"

This example simply demonstrates the difference betwen the :basic and
the :gregorian calendars. The problem is that the 60.years function
is also using the :basic calendar, so it stands to reason that t.ago
produces the boring response of "60 years, 18 seconds ago".

To really see the difference between them, we'd need to use some
point in time, such as 3 billion seconds ago:

t = Time.now - 3000000000
=> Thu May 28 15:15:22 +1000 1914

t.ago :focus => :second, :calendar => :basic
=> "95 years, 1 month, 2 weeks, 3 days, 5 hours, 20 minutes, 10 seconds ago"

t.ago :focus => :second, :calendar => :gregorian
=> "95 years, 3 weeks, 3 days, 2 hours, 43 minutes, 8 seconds ago"

Sure, it's only a 3 week difference over 95 years, but they're three
weeks that never actually occurred.

Using the Gregorian calendar is also a bit more accurate because it
converts Time.now to a Float rather than a Fixnum. This means that
Time.now is calculated down to 100,000 microseconds:

Time.now.to_f
=> 1245495041.70918


=== Numbers to Time

==== Fixnums

The other aspect of the Ago method, which you've already explored a
little bit, is the ability to convert units of time to seconds
and time objects, like this:

5.years
=> 157680000

3.months
=> 7776000

6.weeks.ago
=> Sat May 09 21:11:25 +1000 2009

20.hours.from_now
=> Sun Jun 21 17:12:01 +1000 2009

These methods work the same in pretty much every case, except that
the years, months, and weeks methods can take the :calendar
option in the manner as we saw above, like this:

5.years :calendar => :basic
=> 157680000

5.years :calendar => :gregorian
=> 157784760.0

5.years(:calendar => :gregorian).ago
=> Sun Jun 20 16:09:46 +1000 2004

5.years(:calendar => :gregorian).from_now
=> Sat Jun 21 02:22:15 +1000 2014


==== Floats and Bignums

The Ago::Numbers methods are also included in the Float and Bignum
classes, and can be called from those as well, such as:

3.2.months.from_now
=> Thu Sep 24 21:18:59 +1000 2009

24.6.years.ago
=> Mon Nov 19 22:19:44 +1100 1984

500.3482.weeks.from_now
=> Tue Jan 22 08:50:19 +1100 2019

OR, to use Bignums:

100000000000.class
=> Bignum

100000000000.minutes
=> 6000000000000

3000000000000.weeks :calendar => :gregorian
=> 1.82059338461538e+18

300000000000000.years(:calendar => :gregorian)
=> 9.4670856e+21

THE CAVEAT here is that you can't use the .ago or .from_now methods
on Bignums, because they're out of range for the Time class:

100000000000.class
=> Bignum

100000000000.seconds.ago
RangeError: time - 100000000000.000000 out of Time range
from ./numbers.rb:6:in `-'
from ./numbers.rb:6:in `ago'


== REQUIREMENTS:

You must have rubygems installed to use Ago as a gem. To install
Rubygems on a debian or ubuntu linux system, do:

sudo aptitude update && sudo aptitude install rubygems

== INSTALL:

=== As a Rubygem

sudo gem install --remote ago

Then, add Ago to your script with:

require 'rubygems'
require 'ago'

=== Directly into your script

If you want to include Ago directly into your script, you can
download Ago as a .tgz or .zip package from the Ago homepage at:

http://ago.rubygems.org

Once you have the package, add Ago to your script's directory, add
the ago directory to your $LOAD_PATH variable...

$LOAD_PATH << "./ago"

.. and require Ago at the top of your script:

require 'ago'

== LICENSE:

(The MIT License)

Copyright (c) 2009 Mike Zazaian

Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
'Software'), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:

The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.