Anonymous Monk has asked for the wisdom of the Perl Monks concerning the following question:

I've ported Rail's time_ago_in_words method: http://apidock.com/rails/v4.2.1/ActionView/Helpers/DateHelper/distance_of_time_in_words Any interest? I've taken a look at Time::Duration and some of the other modules, but none of them seem to behave as nicely as Rail's for giving approximate durations.

Replies are listed 'Best First'.
Re: Perl Time Ago in Words
by ww (Archbishop) on Jul 05, 2015 at 12:16 UTC

    Working from bottom to top, some suggestions for making this post more useful:

    • Tell us a bit more about the meaning (as used here) of "approximate." Is 15 days approximately "a week" ... or "a month?" Does 183 days approximate "a year?" What number of seconds become (roughly) "a minute?"
    • Re "Any interest:" A clear and somewhat more expansive announcement would probably generate more interest.
    • Re the address: better provided as a link -- see Markup in the Monastery and note also that while a site cited largely answers the questions, content here is durable; the Wise Monks who first offered guidance on the matter were concerned that off-site links may not be long-lasting.

    IOW, I think you can sum up these observations as a call to "write a better tease" ...
            and, that said, yes, I, for one, find this so interesting1 as to be persuaded to upvote a post whose content seems (to me) in serious need of improvement.

    Update:   1 Where the value of "interesting" is "how does the code handle the many edge cases?"

      Sorry my message was lacking.

      The module is currently available here: https://github.com/mla/time-ago

      Namespace suggestions welcome. I also put it on PrePan http://prepan.org/module/nY5Y569jtrb

      Some examples of what approximate means:

      #!/usr/bin/env perl use strict; use warnings; use Time::Ago; my $hour = 60 * 60; my $day = 86400; foreach (0, 65, $hour * 3.5, $day * 376, $day * 365 * 14.7) { printf "%10s secs: %s\n", $_, Time::Ago->in_words($_); }

      Output:

      0 secs: less than 1 minute 65 secs: 1 minute 12600 secs: about 4 hours 32486400 secs: about 1 year 463579200 secs: over 14 years

      The precise rules are detailed on the github page.

        You should offer to merge your code with Time::Duration. Maybe as a sub-module -- Time::Duration::Ago (sweet!)

        Remember: Ne dederis in spiritu molere illegitimi!

        Suggestion: although it deviates from the original (rail) version:

        Change the singulars from "1 unit" to "a unit", at least for the minutes
        (or change the 65 seconds to "about 1 minute").

        This would be more consistent. And "1 minute" sounds more exact than it is :-)

Re: Perl Time Ago in Words
by Your Mother (Archbishop) on Jul 06, 2015 at 18:35 UTC

    Have you looked at DateTime::Format::Human::Duration? It's what I've been using for a few years now and I wouldn't turn to anything else unless it was similar + improved performance (DateTime stuff is relatively slow), and even then I might not because I like working with DateTime objects.

      Yes, I had seen that. It looked very similar to Time::Duration except that it's based on DateTime.

      Here's a script comparing Time::Duration, DateTime::Format::Human::Duration, and Time::Ago for various durations.

      #!/usr/bin/env perl use strict; use warnings; use lib 'lib'; use DateTime; use DateTime::Format::Human::Duration; use Time::Ago; use Time::Duration; my $hour = 60 * 60; my $day = $hour * 24; my $month = $day * 30; my @durations = ( 0, 38, 60 * 4, $hour * 3.8, $month * 7, $month * 23, $month * 28, ); my $class = 'Human::Duration'; foreach (@durations) { my $dt1 = DateTime->from_epoch(epoch => time - $_); my $dt2 = DateTime->from_epoch(epoch => time); my $diff = $dt2 - $dt1; print "Seconds: $_\n"; printf "%-25s %s\n", ' Time::Ago', Time::Ago->in_words($diff); print "\n"; my $class = ' Human::Duration'; printf "%-25s %s\n", "$class #1", DateTime::Format::Human::Duration->new->format_duration($diff); printf "%-25s %s\n", "$class #2", DateTime::Format::Human::Duration->new->format_duration( $diff, units => [qw/ years months /], ); printf "%-25s %s\n", "$class #3", DateTime::Format::Human::Duration->new->format_duration( $diff, precision => 'years', ); print "\n"; $class = ' Time::Duration'; printf "%-25s %s\n", "$class #1", Time::Duration::ago($_); printf "%-25s %s\n", "$class #1", Time::Duration::ago($_, 1); print "\n\n"; }

      Output:

      Seconds: 0 Time::Ago less than a minute Human::Duration #1 no time Human::Duration #2 no time Human::Duration #3 no time Time::Duration #1 right now Time::Duration #2 right now Seconds: 38 Time::Ago 1 minute Human::Duration #1 38 seconds Human::Duration #2 no time Human::Duration #3 no time Time::Duration #1 38 seconds ago Time::Duration #2 38 seconds ago Seconds: 240 Time::Ago 4 minutes Human::Duration #1 4 minutes Human::Duration #2 no time Human::Duration #3 no time Time::Duration #1 4 minutes ago Time::Duration #2 4 minutes ago Seconds: 13680 Time::Ago about 4 hours Human::Duration #1 3 hours and 48 minutes Human::Duration #2 no time Human::Duration #3 no time Time::Duration #1 3 hours and 48 minutes ago Time::Duration #2 4 hours ago Seconds: 18144000 Time::Ago 7 months Human::Duration #1 6 months, 4 weeks, and 1 day Human::Duration #2 6 months Human::Duration #3 no time Time::Duration #1 210 days ago Time::Duration #2 210 days ago Seconds: 59616000 Time::Ago almost 2 years Human::Duration #1 1 year, 10 months, 3 weeks, and 1 day Human::Duration #2 1 year and 10 months Human::Duration #3 1 year Time::Duration #1 1 year and 325 days ago Time::Duration #2 2 years ago Seconds: 72576000 Time::Ago over 2 years Human::Duration #1 2 years, 3 months, 2 weeks, and 5 days Human::Duration #2 2 years and 3 months Human::Duration #3 2 years Time::Duration #1 2 years and 110 days ago Time::Duration #2 2 years ago

      You can see that Time::Ago is much more lax in it's approximation, always returning just a single, rounded unit.

      The use-case for this is when precision is not especially important. e.g., for when a comment was made on a website, etc.

      The latest version of T::A on github is now using Locale::TextDomain for localization, and support has been added for handling DateTime::Duration objects directly.

Re: Perl Time Ago in Words
by Anonymous Monk on Jul 05, 2015 at 18:41 UTC
    CPAN awaits your contribution!
Re: Perl Time Ago in Words
by mla12 (Acolyte) on Jul 18, 2015 at 23:12 UTC

    Updated to use Locale::TextDomain for localization. French, German, Italian, Japanese, Russian, and Spanish translations have been added.

    https://github.com/mla/time-ago