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

Mighty Perlmonks,

I have an x amount of seconds and would like to print it in a smart, human readable and intuitive format:

For instance:
# no need to write days, hours, seconds but # write minute in singular $ perl nice-epoch 60 1 minute # both second and minute is written singular $ perl nice-epoch 61 1 minute, 1 second # write minute in singular $ perl nice-epoch 62 in 1 minute, 2 seconds # no need to write days/hours or seconds but # write seconds in plural $ perl nice-epoch 120 in 2 minutes # no need to write hours, minutes, seconds $ perl nice-epoch 65400005465 in 756944 days

I tried to write something like that on my own based on 101511 but with all the plural/singular, is it zero or not it gets endless complicated and I wonder if any of you could recommend a already existing module.

Rakzer

Replies are listed 'Best First'.
Re: smart human readable time epoch
by Anonymous Monk on Jun 15, 2011 at 09:01 UTC
      Usage:
      use DateTime::Format::Human::Duration qw( ); my $formatter = DateTime::Format::Human::Duration->new(); sub format_duration { my ($dur) = @_; return $formatter->format_duration($dur, past => '%s ago', future => 'in %s', no_time=> 'now', ); }

      Creating the argument is done using the same code as Re: smart human readable time epoch.

      I'm still getting bad results, though. I think the module has a few bugs.

      I tried that one but i get:
      perl -e 'use DateTime; use DateTime::Format::Human::Duration; my $span + = DateTime::Format::Human::Duration->new(); print $span->format_dura +tion(234234234);' Can't call method "in_units" without a package or object reference at +/usr/local/lib/perl5/site_perl/5.12.3/DateTime/Format/Human/Duration. +pm line 27.
      Not sure if it's cruft or missing something. That's with perl v5.12.3.
        What you're missing is the proper usage of the function. It is documented to take a DateTime::Duration object.
Re: smart human readable time epoch
by ikegami (Patriarch) on Jun 15, 2011 at 09:07 UTC

    Do you want to assume that all days have 24 hours and all minutes have 60 seconds, or do you want to use here and now as a starting point?


    If you want to use here and now as a starting point:

    Downside: The result won't be accurate if it's really relative to another reference point.

    use DateTime qw( ); { my $now = DateTime->now( time_zone => 'local' ); ( my $dt = $now->clone ) ->add( seconds => $ARGV[0] ); print format_duration($dt - $now), "\n"; }

    Note that you can extend this to months and years if you wanted.


    If you don't want to use a starting point:

    Downside: Incorrectly assumes every day has 24 hours and every minute has 60 seconds.

    use DateTime::Duration qw( ); { my $secs = $ARGV[0]; my $dur = DateTime::Duration->new( days => int($secs/(24*60*60)), hours => int($secs/(60*60))%24, minutes => int($secs/60)%60, seconds => $secs%60, ); print format_duration($dur), "\n"; }

    Note that you can extend this to weeks if you wanted.


    Common code:

    sub human_list { my $last = pop; return @_ ? join(', ', @_) . " and $last" : $last; } my @units = ( [qw( day days )], [qw( hour hours )], [qw( minute minutes )], [qw( second seconds )], ); my @units_plural = map $_->[1], @units; sub format_duration { my ($dur) = @_; my %parts; @parts{@units_plural} = $dur->in_units(@units_plural); my @parts; for (@units) { my ($singular, $plural) = @$_; if ($parts{$plural} == 1) { push @parts, "1 $singular"; } elsif ($parts{$plural} >= 1) { push @parts, "$parts{$plural} $plural"; } } return @parts ? 'in ' . human_list(@parts) : 'now'; }
Re: smart human readable time epoch
by ambrus (Abbot) on Jun 15, 2011 at 09:28 UTC
Re: smart human readable time epoch
by jpl (Monk) on Jun 15, 2011 at 10:38 UTC