My Favorite Modules: Time::Piece

Time::Piece is a date/time module that replaces the built-in functions gmtime() and localtime(). The replaced functions return a Time::Piece object, with accessors for the compontents of the time. Time::Piece also provides formatting, parsing, and arithmetic.

This module has been in core since Perl 5.9.5. I was able to get it to pass tests as far back as 5.8.1, though not 5.8.0 or 5.6.2.

Without this module, you would obtain the current Gregorian year in your local zone like this

my $year = ( localtime() )[5] + 1900;

or maybe

my ( undef, undef, undef, undef, undef, $year ) = localtime();
$year += 1900;

Neither is particularly self-documenting, and the latter is much more verbose than we expect of Perl.

But with Time::Piece, the code looks like this:

use Time::Piece;

my $year = localtime->year();

Yes, this actually gives you the Gregorian year. If you want the Perl year (Gregorian - 1900), you can use the _year() method instead. This is documented and therefore public, despite the leading underscore.

There are, of course, accessors for everything returned by the replaced core functions. In cases where the core function returns a value offset from the usually-displayed value, there are accessors for both.

Date arithmetic is implemented using operator overloading. Subtracting a Time::Piece from another yields a Time::Seconds object, which is also part of the Time-Piece distribution. You can also add seconds to a Time::Piece. Arithmetic takes account of summer time. If executed in zone America/New_York, the following

use 5.010;

use Time::Local;
use Time::Piece;

# Noon the day before the switch to daylight saving time (in America/New_York)
my $before = localtime( timelocal( 0, 0, 12, 12, 2, 2022 ) );
# Noon the day of the switch to daylight saving time (in America/New_York)
my $after = localtime( timelocal( 0, 0, 12, 13, 2, 2022 ) );

say 'Before: ', $before->strftime();
say ' After: ', $after ->strftime();
my $delta = $after - $before; # A Time::Seconds
say ' Delta: ', $delta->pretty(); # Only 23 hours.

prints

Before: Sat, 12 Mar 2022 12:00:00 EST
 After: Sun, 13 Mar 2022 12:00:00 EDT
 Delta: 23 hours, 0 minutes, 0 seconds

Note that Time::Piece is smart enough to handle objects from different zones. If one of the calls to localtime() in the above code is changed to gmtime() the corresponding time output will change, but the delta will remain the same.

The strftime() method takes the same format string as the strftime() POSIX subroutine, but without needing to load the POSIX module.

Date parsing is strptime()-style, and by default only parses American English. You can change this to your locale by calling Time::Piece->use_locale();, but be aware that this is a global setting.

Previous entries in this series:

  1. if
  2. diagnostics
  3. Term::ReadLine::Perl
  4. re
  5. Devel::NYTProf
  6. Errno

Leave a comment

About Tom Wyant

user-pic I blog about Perl.