Skip Menu |

This queue is for tickets about the DateTime-Format-Human-Duration CPAN distribution.

Report information
The Basics
Id: 76497
Status: resolved
Priority: 0/
Queue: DateTime-Format-Human-Duration

People
Owner: Nobody in particular
Requestors: stratman [...] gmail.com
Cc: webmaster [...] simplemood.com
AdminCc:

Bug Information
Severity: Wishlist
Broken in: 0.0.3
Fixed in: (no value)



CC: webmaster [...] simplemood.com
Subject: Controlling which units are used
I'm currently using some crude workarounds elsewhere to achieve this, but perhaps it would be useful to be able to control which units are used in the formatted strings. Two specific scenarios to consider: * Resolution: the max number of units to use. e.g. '1y 2mo 23d 14h' with a resolution of 2 would yield '1y 2mo' * smallest unit: e.g. with a smallest unit of 'month' '1y 2mo 23d' becomes '1y 2mo' My first reaction is to add these as options that can be passed to format_duration() and format_duration_between() Any thoughts or opposition?
From: au [...] hcsd.de
Hi, this is my suggestion... The appended patch adds two standard arguments: 'units' and 'precision': The argument 'units' allows to specify which units will be passed to DateTime::Format's in_unit() method. Example: my $fmt = DateTime::Format::Human::Duration->new(); my $d = DateTime::Duration->new(...); my $s = $fmt->format_duration($d, 'units' => [qw/years months days/] ); $s now is a string that includes years, months, and days only. 'precision' keeps the given or default units but removes all units above the given time resolution. So if you want to see the duration in minute resolution only (no seconds and nanoseconds): $fmt->format_duration($d, 'precision' => 'days'); $s is now '1 year, 7 months, 2 weeks, and 2 days'. I've also added some documentation (POD). See there for more details. Or take a look at the code. Stephan Am Mi 11. Apr 2012, 13:50:36, MSTRAT schrieb: Show quoted text
> I'm currently using some crude workarounds elsewhere to achieve this, > but perhaps it would be > useful to be able to control which units are used in the formatted > strings. > > Two specific scenarios to consider: > * Resolution: the max number of units to use. e.g. '1y 2mo 23d 14h' > with a resolution of 2 would > yield '1y 2mo' > * smallest unit: e.g. with a smallest unit of 'month' '1y 2mo 23d' > becomes '1y 2mo' > > My first reaction is to add these as options that can be passed to > format_duration() and > format_duration_between() > > Any thoughts or opposition?
Subject: units_and_precision.patch
diff -u --recursive DateTime/Format/Human/Duration.pm /home/austest/dev/SMF/lib/DateTime/Format/Human/Duration.pm --- DateTime/Format/Human/Duration.pm 2012-07-05 15:36:12.000000000 +0200 +++ /home/austest/dev/SMF/lib/DateTime/Format/Human/Duration.pm 2012-07-12 10:53:09.691591209 +0200 @@ -6,6 +6,21 @@ our $VERSION = '0.51'; +use constant { + PLMAP => { + 'years' => [ 'year', 'years' ], + 'months' => [ 'month', 'months' ], + 'weeks' => [ 'week', 'weeks' ], + 'days' => [ 'day', 'days' ], + 'hours' => [ 'hour', 'hours' ], + 'minutes' => [ 'minute', 'minutes' ], + 'seconds' => [ 'second', 'seconds' ], + 'nanoseconds' => [ 'nanosecond', 'nanoseconds' ], + }, +}; + +use Carp qw/croak/; + sub new { bless { 'locale_cache' => {} }, 'DateTime::Format::Human::Duration'; } @@ -23,8 +38,19 @@ sub format_duration { my ($span, $duration, %args) = @_; + + my @units = $args{'units'} ? @{ $args{'units'} } : qw(years months weeks days hours minutes seconds nanoseconds); + + if ($args{'precision'}) { + # Reduce time resolution to requested precision + for (my $i = 0; $i < scalar(@units); $i++) { + next unless ($units[$i] eq $args{'precision'}); + splice(@units, $i + 1); + } + croak('Useless precision') unless (@units); + } - my @raw = $duration->in_units( qw(years months weeks days hours minutes seconds nanoseconds) ); + my @raw = $duration->in_units( @units ); my @n = map { abs($_) } @raw; # no negative numbers my $say = ''; @@ -86,17 +112,12 @@ # reorder @n use if appropriate for locale # @n has been pass through abs() so that its never negative - my @parts = grep { $_ } ( - $n[0] ? ( $n[0]. ' ' . ($n[0] == 1 ? $setup->{'year'} : $setup->{'years'})) : '', - $n[1] ? ( $n[1] . ' ' .($n[1] == 1 ? $setup->{'month'} : $setup->{'months'})) : '', - $n[2] ? ( $n[2] . ' ' .($n[2] == 1 ? $setup->{'week'} : $setup->{'weeks'})) : '', - $n[3] ? ( $n[3] . ' ' .($n[3] == 1 ? $setup->{'day'} : $setup->{'days'})) : '', - $n[4] ? ( $n[4] . ' ' .($n[4] == 1 ? $setup->{'hour'} : $setup->{'hours'})) : '', - $n[5] ? ( $n[5] . ' ' .($n[5] == 1 ? $setup->{'minute'} : $setup->{'minutes'})) : '', - $n[6] ? ( $n[6] . ' ' .($n[6] == 1 ? $setup->{'second'} : $setup->{'seconds'})) : '', - $n[7] ? ( $n[7] . ' ' .($n[7] == 1 ? $setup->{'nanosecond'} : $setup->{'nanoseconds'})) : '', - ); - + my @parts; + for (my $i = 0; $i < scalar(@units); $i++) { + next unless ($n[$i]); + push(@parts, $n[$i] . ' ' . $setup->{ PLMAP->{ $units[$i] }->[ $n[$i] == 1 ? 0 : 1 ] }); + } + my $no_time = exists $args{'no_time'} ? $args{'no_time'} : $setup->{'no_time'}; return $no_time if !@parts; @@ -192,6 +213,40 @@ =back +=item 3 Time Resolution and Units + +=over 4 + +=item * Units + +Specify units to format duration with. Arguments will be passed to DateTime::Format's in_unit() method. + +Example: + + my $fmt = DateTime::Format::Human::Duration->new(); + my $d = DateTime::Duration->new(...); + + my $s = $fmt->format_duration($d, 'units' => [qw/years months days/] ); + # $s == '1 year, 7 months, and 16 days' + +=item * precision + +By default, the duration will be formatted using nanosecond resolution. Resolution can be reduced by passing +'years', 'months', 'weeks', 'days', 'hours', 'minutes', or 'seconds' to the 'precision' argument. + +Example: + + my $fmt = DateTime::Format::Human::Duration->new(); + my $d = DateTime::Duration->new(...); + + my $a = $fmt->format_duration($d); + # $a == '1 year, 7 months, 2 weeks, 2 days, 9 hours, 43 minutes, and 15 seconds' + + my $b = $fmt->format_duration($d, 'precision' => 'days'); + # $b == '1 year, 7 months, 2 weeks, and 2 days' + +=back + If duration is baseless (IE ambiguouse) then 'past' and 'future' is used based on if $dur->in_units has negatives or not. Also by nature it's not split into type groups:
Thanks, that's great. I've incorporated both arguments, along with some other related changes. Should be resolved in 0.60 now. Thanks again.