DateTime::Format::Duration - Format and parse DateTime::Durations
use DateTime::Format::Duration;
$d = DateTime::Format::Duration->new( pattern => '%Y years, %m months, %e days, '. '%H hours, %M minutes, %S seconds' ); print $d->format_duration( DateTime::Duration->new( years => 3, months => 5, days => 1, hours => 6, minutes => 15, seconds => 45, nanoseconds => 12000 ) ); # 3 years, 5 months, 1 days, 6 hours, 15 minutes, 45 seconds
$duration = $d->parse_duration( '3 years, 5 months, 1 days, 6 hours, 15 minutes, 45 seconds' ); # Returns DateTime::Duration object
print $d->format_duration_from_deltas( years => 3, months => 5, days => 1, hours => 6, minutes => 15, seconds => 45, nanoseconds => 12000 ); # 3 years, 5 months, 1 days, 6 hours, 15 minutes, 45 seconds %deltas = $d->parse_duration_as_deltas( '3 years, 5 months, 1 days, 6 hours, 15 minutes, 45 seconds' ); # Returns hash: # (years=>3, months=>5, days=>1, hours=>6, minutes=>15, seconds=>45)
This module formats and parses DateTime::Duration objects as well as other durations representations.
This module contains a single constructor:
new( ... )
The new
constructor takes the following attributes:
pattern =
$string>
<normalise =
$one_or_zero_or_ISO>>
<normalize =
$one_or_zero_or_ISO>>
This determines whether durations are 'normalised'. For example, does 120 seconds become 2 minutes?
Setting this value to true without also setting a base
means we will
normalise without a base. See the /Normalising without a base section
below.
<base =
$datetime_object>>
DateTime::Format::Duration has the following methods:
format_duration( $datetime_duration_object )
<format_duration( duration =
$dt_duration, pattern => $pattern )>>
format_duration_from_deltas( %deltas )
format_duration_from_deltas( %deltas, pattern =
$pattern )>
years, months, days, hours, minutes, seconds
and nanoseconds
as well as negative
which, if true, inverses the duration. (years => -1
is
the same as years => 1, negative=>1
)
parse_duration( $string )
parse_duration_as_deltas( $string )
normalise( $duration_object )
normalize( %deltas )
pattern()
base()
normalising()
All setters return the object so that they can be strung together.
set_pattern( $new_pattern )
set_base( $new_DateTime )
set_normalising( $true_or_false_or_ISO )
This module uses a similar set of patterns to strftime. These patterns have been kept as close as possible to the original time-based patterns.
Precision can be changed for any and all the above values. For all but nanoseconds (%N), the precision is the zero-padding. To change the precision insert a number between the '%' and the letter. For example: 1 year formatted with %6Y would return 000001 rather than the default 0001. Likewise, to remove padding %1Y would just return a 1.
Nanosecond precision is the other way (nanoseconds are fractional and thus should be right padded). 123456789 nanoseconds formatted with %3N would return 123 and formatted as %12N would return 123456789000.
This module contains a complex method for normalising durations. The method ensures that the vslues for all components are as close to zero as possible. Rather than returning 68 minutes, it is normalised to 1 hour, 8 minutes.
The complexity comes from three places:
The duration of 1 day, minus 2 hours is easy to normalise in your head to 22 hours. However consider something more complex such as -2 years, +1 month, +22 days, +11 hours, -9 minutes.
This module works from lowest to highest precision to calculate the duration.
So, based on a base
of 2004-03-28T00:00:00 the following transformations take
place:
2003-01-01T00:00:00 - 2 years = 2001-01-01T00:00:00 === -2 years 2001-01-01T00:00:00 + 1 month = 2001-02-01T00:00:00 === -1 year, 11 months 2001-02-01T00:00:00 + 22 days = 2001-02-23T00:00:00 === -1yr, 10mths, 6days 2001-02-22T00:00:00 + 11 hours = 2001-02-23T11:00:00 === -1y, 10m, 6d, 13h 2001-02-22T11:00:00 - 9 minutes = 2001-02-23T10:51:00 === -1y, 10m, 6d, 13h, 9m
Figure 1 illustrates that, with the given base, -2 years, +1 month, +22 days, +11 hours, -9 minutes is normalised to -1 year, 10 months, 6 days, 13 hours and 9 minutes.
Components will always be assessed from lowest to highest precision (years, months, days, hours, minutes, seconds, nanoseconds). This can really change things.
Consider the duration of 1 day, 24 hours. Normally this will normalise to 2 days. However, consider changes to Daylight Savings. On the changes to and from DST days have 25 and 23 hours.
If we take the base DateTime as midnight on the day DST ends (when there's 25 hours in the day), and add 1 day, 24 hours we end up at midnight 2 days later. So our duration normalises to two days.
However, if we add 24 hours, 1 day we end up at 11pm on the next day! Why is this? Because midnight + 24 hours = 11pm (there's 25 hours on this day!), then we add 1 day and end up at 11pm on the following day.
Figure 2 illustrates the above problem on timelines.
Leap years and seconds further add to the confusion in normalisation. Leap seconds mean there are minutes that are 61 seconds long, thus 130 seconds can be 2 minutes, 10 seconds or 2 minutes 9 seconds, depending on the base DateTime. Simmilarly leap years mean a day can have 23, 24 or 25 hours.
Figure 3 shows how leaps are calculated on timelines.
This module includes two ways to normalise without a base.
This module can bypass duration objects and just work with delta hashes. This used to be of greatest value with earlier versions of DateTime::Duration when DateTime::Duration assumed a duration with one negative component was a negative duration (that is, -2 hours, 34 minutes was assumed to be -2 hours, -34 minutes).
These extra methods have been left in here firstly for backwards-compatibility but also as an added 'syntactic sugar'. Consider these two equivelent expressions:
$one = $o->format_duration( DateTime::Duration->new( years => -2, days => 13, hours => -1 ) );
$two = $o->format_duration_from_deltas( years => -2, days => 13, hours => -1 );
These both create the same string in $one and $two, but if you don't already have a DateTime::Duration object, the later looks cleaner.
Rick Measham <rickm@cpan.org>
Copyright (c) 2003 - 2004 Rick Measham. All rights reserved. This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself.
The full text of the license can be found in the LICENSE file included with this module.
datetime@perl.org mailing list
http://datetime.perl.org/