#!/usr/bin/perl -w
use strict;
# Emulate:
# $ date -d "Tue, 01 Jan 2013 16:05:53 +0000"
# Tue Jan 1 10:05:53 CST 2013
use Time::Local qw< timegm >;
use POSIX qw< strftime >;
my @Mons = qw< jan feb mar apr may jun jul aug sep oct nov dec >;
my %Mons; @Mons{@Mons} = 1..@Mons;
print datetime_offset2local( "@ARGV" ), $/;
exit;
sub datetime_offset2local {
my( $date ) = @_;
# Parse out the date parts:
my( $dow, $day, $mon, $yr, $time, $off, $ex ) = split /,? /, $date
+, -1;
die "Too many fields ($ex) in input datetime ($date)\n"
if defined $ex;
my( $hr, $min, $sec ) = split /:/, $time;
$mon = $Mons{ lc $mon }
|| die "Invalid month name ($mon): $date\n";
# Convert input date to epoch seconds (ignoring GMT offset):
$sec = timegm( $sec, $min, $hr, $day, $mon-1, $yr );
# Parse the GMT offset and apply it:
( my $sign, $hr, $min ) = $off =~ /^([-+])([0-9][0-9])([0-9]*)$/
or die "Invalid offset ($off): $date\n";
$off = $hr*60;
$off += $min || 0;
$off *= 60;
$off *= -1
if '-' eq $sign;
# Convert epoch seconds to string using local time zone and locale
+:
return strftime( "%a, %b %d %Y %T %Z (%z)", localtime( $sec - $off
+ ) );
}
__END__
$ TZ=US/Central perl offset2local.pl Tue, 01 Jan 2013 16:05:53 +0000
Tue, Jan 01 2013 10:05:53 CST (-0600)
$ TZ=US/Central perl offset2local.pl Tue, 01 Jan 2013 16:05:53 -0600
Tue, Jan 01 2013 16:05:53 CST (-0600)
$ perl offset2local.pl Tue, 01 Jan 2013 16:05:53 +0000
Tue, Jan 01 2013 08:05:53 PST (-0800)
Time::Local is a core module. The only reason I used POSIX was to get the timezone abbreviation ("CST"); otherwise, that last step could have been easily done with just localtime and sprintf).