cpan intermediate

How to use DateTime::Duration for time periods in Perl?

Question

How to use DateTime::Duration for time periods in Perl?

DateTime::Duration is a module from the DateTime suite that represents a span of time or duration between two DateTime objects in Perl. It excels at expressing periods in units like years, months, days, hours, minutes, and seconds—all in a structured, object-oriented way.

Understanding DateTime::Duration

A DateTime::Duration object stores time intervals broken down into individual parts: years, months, weeks, days, hours, minutes, seconds, and nanoseconds. Unlike a simple numeric count of seconds, it maintains these separate units so you can work with complex durations like “2 years, 3 months, and 5 days” intuitively.

Internally, the object stores fields as named arguments, reflecting how durations are often presented in human contexts. This helps when adding or subtracting durations to and from DateTime objects while respecting calendar peculiarities (e.g., varying month lengths).

Basic usage

  • Create a new duration by specifying any combination of components.
  • Use methods like in_units to extract specific parts as a list or hash.
  • Add or subtract it from DateTime objects to obtain new timestamps.

Example: Creating and Inspecting a Duration


use strict;
use warnings;
use DateTime;
use DateTime::Duration;

# Construct a duration of 1 year, 2 months, 3 days, 4 hours, 5 minutes, and 6 seconds
my $duration = DateTime::Duration->new(
    years   => 1,
    months  => 2,
    days    => 3,
    hours   => 4,
    minutes => 5,
    seconds => 6,
);

# Print the raw duration components
print "Duration parts:\n";
print "Years: $duration->{years}\n";
print "Months: $duration->{months}\n";
print "Days: $duration->{days}\n";
print "Hours: $duration->{hours}\n";
print "Minutes: $duration->{minutes}\n";
print "Seconds: $duration->{seconds}\n";

# Create a starting DateTime instance
my $start = DateTime->new(year => 2020, month => 1, day => 1, hour => 0, minute => 0);

# Add the duration to the start
my $end = $start + $duration;

print "Start date/time: ", $start->datetime, "\n";
print "End date/time after adding duration: ", $end->datetime, "\n";

# Extract units from duration - returns array in order of units
my @units = $duration->in_units('years', 'months', 'days', 'hours', 'minutes', 'seconds');
print "Units from in_units method: ", join(", ", @units), "\n";

Notes and Gotchas

  • Non-uniform units: Months and years are variable length (months can be 28-31 days, years can be leap). DateTime::Duration stores them separately and does not convert to a fixed number of seconds.
  • Adding durations: When adding a DateTime::Duration to a DateTime object, Perl handles calendar logic internally (like month rollovers).
  • Negative durations: You can also specify negative values to represent durations backward in time.
  • Version compatibility: DateTime::Duration has been consistent across Perl 5.8+ but ensure you use a compatible DateTime version.
  • Units in in_units: The in_units method accepts a list of units you'd like to extract. Missing units default to zero.

Summary

DateTime::Duration is a flexible way to represent complex durations in multiple units suitable for calendrical calculations rather than mere seconds counting. Combined with DateTime, it lets you add or subtract human-friendly time intervals while automatically handling irregular lengths like leap years and months varying in length.

Verified Code

Executed in a sandbox to capture real output. • v5.34.1 • 213ms

Tip: edit code and use “Run (Browser)”. Server runs always execute the published, verified snippet.
STDOUT
Duration parts:
Years: 
Months: 14
Days: 3
Hours: 
Minutes: 245
Seconds: 6
Start date/time: 2020-01-01T00:00:00
End date/time after adding duration: 2021-03-04T04:05:06
Units from in_units method: 1, 2, 3, 4, 5, 6
STDERR
Use of uninitialized value in concatenation (.) or string at - line 18.
Use of uninitialized value in concatenation (.) or string at - line 21.

Was this helpful?

Related Questions