use DateTime::Duration; $dur = DateTime::Duration->new( years => 3, months => 5, weeks => 1, days => 1, hours => 6, minutes => 15, seconds => 45, nanoseconds => 12000, end_of_month => 'limit', ); my ( $days, $hours, $seconds ) = $dur->in_units( 'days', 'hours', 'seconds' ); # Human-readable accessors, always positive, but consider using # DateTime::Format::Duration instead $dur->years; $dur->months; $dur->weeks; $dur->days; $dur->hours; $dur->minutes; $dur->seconds; $dur->nanoseconds; $dur->is_wrap_mode; $dur->is_limit_mode; $dur->is_preserve_mode; print $dur->end_of_month_mode; # Multiply all values by -1 my $opposite = $dur->inverse; my $bigger = $dur1 + $dur2; my $smaller = $dur1 - $dur2; # the result could be negative my $bigger = $dur1 * 3; my $base_dt = DateTime->new( year => 2000 ); my @sorted = sort { DateTime::Duration->compare( $a, $b, $base_dt ) } @durations; if ( $dur->is_positive ) {...} if ( $dur->is_zero ) {...} if ( $dur->is_negative ) {...}
See the How DateTime Math Works section of the DateTime documentation for more details. The short course: One cannot in general convert between seconds, minutes, days, and months, so this class will never do so. Instead, create the duration with the desired units to begin with, for example by calling the appropriate subtraction/delta method on a DateTime object.
"DateTime::Duration" has the following methods:
An integer containing the number of years in the duration. This is optional.
An integer containing the number of months in the duration. This is optional.
An integer containing the number of weeks in the duration. This is optional.
An integer containing the number of days in the duration. This is optional.
An integer containing the number of hours in the duration. This is optional.
An integer containing the number of minutes in the duration. This is optional.
An integer containing the number of seconds in the duration. This is optional.
An integer containing the number of nanoseconds in the duration. This is optional.
This must be either "wrap", "limit", or "preserve". This parameter specifies how date math that crosses the end of a month is handled.
In "wrap" mode, adding months or years that result in days beyond the end of the new month will roll over into the following month. For instance, adding one year to Feb 29 will result in Mar 1.
If you specify "limit", the end of the month is never crossed. Thus, adding one year to Feb 29, 2000 will result in Feb 28, 2001. If you were to then add three more years this will result in Feb 28, 2004.
If you specify "preserve", the same calculation is done as for "limit" except that if the original date is at the end of the month the new date will also be. For instance, adding one month to Feb 29, 2000 will result in Mar 31, 2000.
For positive durations, this parameter defaults to "wrap". For negative durations, the default is "preserve". This should match how most people ``intuitively'' expect datetime math to work.
All of the duration units can be positive or negative. However, if any of the numbers are negative, the entire duration is negative.
All of the numbers must be integers.
Internally, years as just treated as 12 months. Similarly, weeks are treated as 7 days, and hours are converted to minutes. Seconds and nanoseconds are both treated separately.
my $dur = DateTime::Duration->new( years => 1, months => 15 ); $dur->in_units('years'); # 2 $dur->in_units('months'); # 27 $dur->in_units( 'years', 'months' ); # (2, 3) $dur->in_units( 'weeks', 'days' ); # (0, 0) !
The last example demonstrates that there will not be any conversion between units which don't have a fixed conversion rate. The only conversions possible are:
For the explanation of why this is the case, please see the How DateTime Math Works section of the DateTime documentation
Note that the numbers returned by this method may not match the values given to the constructor.
In list context, "$dur->in_units" returns the lengths in the order of the units given. In scalar context, it returns the length in the first unit (but still computes in terms of all given units).
If you need more flexibility in presenting information about durations, please take a look a DateTime::Format::Duration.
If the duration contains both positive and negative units, then it will return false for all of these methods.
You can set the end of month mode in the inverted duration explicitly by passing an "end_of_month" parameter to the "$dur->inverse" method.
If no base datetime is given, then the result of "DateTime->now" is used instead. Using this default will give non-repeatable results if used to compare two duration objects containing different units. It will also give non-repeatable results if the durations contain multiple types of units, such as months and days.
However, if you know that both objects only consist of one type of unit (months or days or hours, etc.), and each duration contains the same type of unit, then the results of the comparison will be repeatable.
Here's what each method returns:
$dur->years == abs( $dur->in_units('years') ) $dur->months == abs( ( $dur->in_units( 'months', 'years' ) )[0] ) $dur->weeks == abs( $dur->in_units( 'weeks' ) ) $dur->days == abs( ( $dur->in_units( 'days', 'weeks' ) )[0] ) $dur->hours == abs( $dur->in_units( 'hours' ) ) $dur->minutes == abs( ( $dur->in_units( 'minutes', 'hours' ) )[0] ) $dur->seconds == abs( $dur->in_units( 'seconds' ) ) $dur->nanoseconds == abs( ( $dur->in_units( 'nanoseconds', 'seconds' ) )[0] )
If this seems confusing, remember that you can always use the "$dur->in_units" method to specify exactly what you want.
Better yet, if you are trying to generate output suitable for humans, use the "DateTime::Format::Duration" module.
Comparison is not overloaded. If you attempt to compare durations using "<=>" or "cmp", then an exception will be thrown! Use the "compare" class method instead.
Bugs may be submitted at <https://github.com/houseabsolute/DateTime.pm/issues>.
There is a mailing list available for users of this distribution, <mailto:datetime@perl.org>.
I am also usually active on IRC as 'autarch' on "irc://irc.perl.org".
This is free software, licensed under:
The Artistic License 2.0 (GPL Compatible)
The full text of the license can be found in the LICENSE file included with this distribution.