in reply to smart human readable time epoch

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'; }