+ $ts = timegm($ss // 0, $mm, $hh, $dd, $mon, $yyyy);
+
+ # Compute the time offset from [+-]HHMM
+ $tz //= 0;
+ my ($tz_hh, $tz_mm);
+ if (length($tz) == 1) {
+ $tz_hh = $tz;
+ $tz_mm = 0;
+ } elsif (length($tz) == 2) {
+ $tz_hh = 0;
+ $tz_mm = $tz;
+ } else {
+ $tz_hh = $tz;
+ $tz_hh =~ s/([0-9]{2})\z//;
+ $tz_mm = $1;
+ }
+ while ($tz_mm >= 60) {
+ $tz_mm -= 60;
+ $tz_hh += 1;
+ }
+ $sign //= '+';
+ my $off = $sign . ($tz_mm * 60 + ($tz_hh * 60 * 60));
+ $ts -= $off;
+ $sign = '+' if $off == 0;
+ $zone = sprintf('%s%02d%02d', $sign, $tz_hh, $tz_mm);
+
+ # Time::Zone and Date::Parse are part of the same distibution,
+ # and we need Time::Zone to deal with tz names like "EDT"
+ } elsif (eval { require Date::Parse }) {
+ $ts = Date::Parse::str2time($date);
+ return undef unless(defined $ts);
+
+ # off is the time zone offset in seconds from GMT
+ my ($ss,$mm,$hh,$day,$month,$year,$off) =
+ Date::Parse::strptime($date);
+ return undef unless(defined $off);
+
+ # Compute the time zone from offset
+ my $sign = ($off < 0) ? '-' : '+';
+ my $hour = abs(int($off / 3600));
+ my $min = ($off / 60) % 60;
+
+ # deal with weird offsets like '-0420' properly
+ $min = 60 - $min if ($min && $off < 0);
+
+ $zone = sprintf('%s%02d%02d', $sign, $hour, $min);
+ } else {
+ warn "Date::Parse missing for non-RFC822 date: $date\n";
+ return undef;
+ }