How can I parse dates and convert time zones in Perl?

Because the Perl built in date handling interfaces are kind of clunky and you wind up passing around a half dozen variables, the better way is to use either DateTime or Time::Piece. DateTime is the all-singing, all-dancing Perl date object, and you’ll probably eventually want to use it, but Time::Piece is simpler and perfectly adequate to this task, has the advantage of shipping with 5.10 and the technique is basically the same for both.

Here’s the simple, flexible way using Time::Piece and strptime.

#!/usr/bin/perl

use 5.10.0;

use strict;
use warnings;

use Time::Piece;

# Read the date from the command line.
my $date = shift;

# Parse the date using strptime(), which uses strftime() formats.
my $time = Time::Piece->strptime($date, "%Y%m%d %H:%M");

# Here it is, parsed but still in GMT.
say $time->datetime;

# Create a localtime object for the same timestamp.
$time = localtime($time->epoch);

# And here it is localized.
say $time->datetime;

And here’s the by-hand way, for contrast.

Since the format is fixed, a regular expression will do just fine, but if the format changes you’ll have to tweak the regex.

my($year, $mon, $day, $hour, $min) = 
    $date =~ /^(\d{4}) (\d{2}) (\d{2})\ (\d{2}):(\d{2})$/x;

Then convert it to Unix epoch time (seconds since Jan 1st, 1970)

use Time::Local;
# Note that all the internal Perl date handling functions take month
# from 0 and the year starting at 1900.  Blame C (or blame Larry for
# parroting C).
my $time = timegm(0, $min, $hour, $day, $mon - 1, $year - 1900);

And then back to your local time.

(undef, $min, $hour, $day, $mon, $year) = localtime($time);

my $local_date = sprintf "%d%02d%02d %02d:%02d\n",
    $year + 1900, $mon + 1, $day, $hour, $min;

Leave a Comment