summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLorry Tar Creator <lorry-tar-importer@lorry>2012-03-30 12:07:25 +0000
committerLorry Tar Creator <lorry-tar-importer@lorry>2012-03-30 12:07:25 +0000
commitf1f9b3164e11c877ed5d509738551a56ac9b37f0 (patch)
tree8199aac0d7e7c5d5470173f422043044504d7c7b
downloadHTTP-Date-tarball-f1f9b3164e11c877ed5d509738551a56ac9b37f0.tar.gz
-rw-r--r--Changes23
-rw-r--r--MANIFEST7
-rw-r--r--META.yml28
-rw-r--r--Makefile.PL48
-rw-r--r--README112
-rw-r--r--lib/HTTP/Date.pm388
-rwxr-xr-xt/date.t180
7 files changed, 786 insertions, 0 deletions
diff --git a/Changes b/Changes
new file mode 100644
index 0000000..7de3e7a
--- /dev/null
+++ b/Changes
@@ -0,0 +1,23 @@
+_______________________________________________________________________________
+2012-03-30 HTTP-Date 6.02
+
+Added support for parsing dates with (faulty) double TZ spec [RT#75150]
+
+Doc tweaks.
+
+
+
+_______________________________________________________________________________
+2012-02-15 HTTP-Date 6.01
+
+Restore perl-5.6 compatiblity. Drop MacOS (classic) support.
+
+
+
+_______________________________________________________________________________
+2011-02-25 HTTP-Date 6.00
+
+Initial release of HTTP-Date as a separate distribution. There are no code
+changes besides incrementing the version number since libwww-perl-5.837.
+
+The HTTP::Date module used to be bundled with the libwww-perl distribution.
diff --git a/MANIFEST b/MANIFEST
new file mode 100644
index 0000000..360176a
--- /dev/null
+++ b/MANIFEST
@@ -0,0 +1,7 @@
+Changes
+lib/HTTP/Date.pm
+Makefile.PL
+MANIFEST This list of files
+README
+t/date.t
+META.yml Module meta-data (added by MakeMaker)
diff --git a/META.yml b/META.yml
new file mode 100644
index 0000000..95e9697
--- /dev/null
+++ b/META.yml
@@ -0,0 +1,28 @@
+--- #YAML:1.0
+name: HTTP-Date
+version: 6.02
+abstract: date conversion routines
+author:
+ - Gisle Aas <gisle@activestate.com>
+license: perl
+distribution_type: module
+configure_requires:
+ ExtUtils::MakeMaker: 0
+build_requires:
+ ExtUtils::MakeMaker: 0
+requires:
+ perl: 5.006002
+ Time::Local: 0
+resources:
+ MailingList: mailto:libwww@perl.org
+ repository: http://github.com/gisle/http-date
+no_index:
+ directory:
+ - t
+ - inc
+generated_by: ExtUtils::MakeMaker version 6.57_05
+meta-spec:
+ url: http://module-build.sourceforge.net/META-spec-v1.4.html
+ version: 1.4
+recommends:
+ Time::Zone: 0
diff --git a/Makefile.PL b/Makefile.PL
new file mode 100644
index 0000000..9279cb6
--- /dev/null
+++ b/Makefile.PL
@@ -0,0 +1,48 @@
+#!perl -w
+
+require 5.006002;
+use strict;
+use ExtUtils::MakeMaker;
+WriteMakefile(
+ NAME => 'HTTP::Date',
+ VERSION_FROM => 'lib/HTTP/Date.pm',
+ ABSTRACT_FROM => 'lib/HTTP/Date.pm',
+ AUTHOR => 'Gisle Aas <gisle@activestate.com>',
+ LICENSE => "perl",
+ MIN_PERL_VERSION => 5.006002,
+ PREREQ_PM => {
+ 'Time::Local' => 0,
+ },
+ META_MERGE => {
+ recommends => {
+ 'Time::Zone' => 0,
+ },
+ resources => {
+ repository => 'http://github.com/gisle/http-date',
+ MailingList => 'mailto:libwww@perl.org',
+ }
+ },
+);
+
+
+BEGIN {
+ # compatibility with older versions of MakeMaker
+ my $developer = -f ".gitignore";
+ my %mm_req = (
+ LICENCE => 6.31,
+ META_MERGE => 6.45,
+ META_ADD => 6.45,
+ MIN_PERL_VERSION => 6.48,
+ );
+ undef(*WriteMakefile);
+ *WriteMakefile = sub {
+ my %arg = @_;
+ for (keys %mm_req) {
+ unless (eval { ExtUtils::MakeMaker->VERSION($mm_req{$_}) }) {
+ warn "$_ $@" if $developer;
+ delete $arg{$_};
+ }
+ }
+ ExtUtils::MakeMaker::WriteMakefile(%arg);
+ };
+}
diff --git a/README b/README
new file mode 100644
index 0000000..5d3e796
--- /dev/null
+++ b/README
@@ -0,0 +1,112 @@
+NAME
+ HTTP::Date - date conversion routines
+
+SYNOPSIS
+ use HTTP::Date;
+
+ $string = time2str($time); # Format as GMT ASCII time
+ $time = str2time($string); # convert ASCII date to machine time
+
+DESCRIPTION
+ This module provides functions that deal the date formats used by the
+ HTTP protocol (and then some more). Only the first two functions,
+ time2str() and str2time(), are exported by default.
+
+ time2str( [$time] )
+ The time2str() function converts a machine time (seconds since
+ epoch) to a string. If the function is called without an argument or
+ with an undefined argument, it will use the current time.
+
+ The string returned is in the format preferred for the HTTP
+ protocol. This is a fixed length subset of the format defined by RFC
+ 1123, represented in Universal Time (GMT). An example of a time
+ stamp in this format is:
+
+ Sun, 06 Nov 1994 08:49:37 GMT
+
+ str2time( $str [, $zone] )
+ The str2time() function converts a string to machine time. It
+ returns `undef' if the format of $str is unrecognized, otherwise
+ whatever the `Time::Local' functions can make out of the parsed
+ time. Dates before the system's epoch may not work on all operating
+ systems. The time formats recognized are the same as for
+ parse_date().
+
+ The function also takes an optional second argument that specifies
+ the default time zone to use when converting the date. This
+ parameter is ignored if the zone is found in the date string itself.
+ If this parameter is missing, and the date string format does not
+ contain any zone specification, then the local time zone is assumed.
+
+ If the zone is not "`GMT'" or numerical (like "`-0800'" or
+ "`+0100'"), then the `Time::Zone' module must be installed in order
+ to get the date recognized.
+
+ parse_date( $str )
+ This function will try to parse a date string, and then return it as
+ a list of numerical values followed by a (possible undefined) time
+ zone specifier; ($year, $month, $day, $hour, $min, $sec, $tz). The
+ $year returned will not have the number 1900 subtracted from it and
+ the $month numbers start with 1.
+
+ In scalar context the numbers are interpolated in a string of the
+ "YYYY-MM-DD hh:mm:ss TZ"-format and returned.
+
+ If the date is unrecognized, then the empty list is returned.
+
+ The function is able to parse the following formats:
+
+ "Wed, 09 Feb 1994 22:23:32 GMT" -- HTTP format
+ "Thu Feb 3 17:03:55 GMT 1994" -- ctime(3) format
+ "Thu Feb 3 00:00:00 1994", -- ANSI C asctime() format
+ "Tuesday, 08-Feb-94 14:15:29 GMT" -- old rfc850 HTTP format
+ "Tuesday, 08-Feb-1994 14:15:29 GMT" -- broken rfc850 HTTP format
+
+ "03/Feb/1994:17:03:55 -0700" -- common logfile format
+ "09 Feb 1994 22:23:32 GMT" -- HTTP format (no weekday)
+ "08-Feb-94 14:15:29 GMT" -- rfc850 format (no weekday)
+ "08-Feb-1994 14:15:29 GMT" -- broken rfc850 format (no weekday)
+
+ "1994-02-03 14:15:29 -0100" -- ISO 8601 format
+ "1994-02-03 14:15:29" -- zone is optional
+ "1994-02-03" -- only date
+ "1994-02-03T14:15:29" -- Use T as separator
+ "19940203T141529Z" -- ISO 8601 compact format
+ "19940203" -- only date
+
+ "08-Feb-94" -- old rfc850 HTTP format (no weekday, no time)
+ "08-Feb-1994" -- broken rfc850 HTTP format (no weekday, no time)
+ "09 Feb 1994" -- proposed new HTTP format (no weekday, no time)
+ "03/Feb/1994" -- common logfile format (no time, no offset)
+
+ "Feb 3 1994" -- Unix 'ls -l' format
+ "Feb 3 17:03" -- Unix 'ls -l' format
+
+ "11-15-96 03:52PM" -- Windows 'dir' format
+
+ The parser ignores leading and trailing whitespace. It also allow
+ the seconds to be missing and the month to be numerical in most
+ formats.
+
+ If the year is missing, then we assume that the date is the first
+ matching date *before* current month. If the year is given with only
+ 2 digits, then parse_date() will select the century that makes the
+ year closest to the current date.
+
+ time2iso( [$time] )
+ Same as time2str(), but returns a "YYYY-MM-DD hh:mm:ss"-formatted
+ string representing time in the local time zone.
+
+ time2isoz( [$time] )
+ Same as time2str(), but returns a "YYYY-MM-DD hh:mm:ssZ"-formatted
+ string representing Universal Time.
+
+SEE ALSO
+ perlfunc, Time::Zone
+
+COPYRIGHT
+ Copyright 1995-1999, Gisle Aas
+
+ This library is free software; you can redistribute it and/or modify it
+ under the same terms as Perl itself.
+
diff --git a/lib/HTTP/Date.pm b/lib/HTTP/Date.pm
new file mode 100644
index 0000000..d05d216
--- /dev/null
+++ b/lib/HTTP/Date.pm
@@ -0,0 +1,388 @@
+package HTTP::Date;
+
+$VERSION = "6.02";
+
+require Exporter;
+@ISA = qw(Exporter);
+@EXPORT = qw(time2str str2time);
+@EXPORT_OK = qw(parse_date time2iso time2isoz);
+
+use strict;
+require Time::Local;
+
+use vars qw(@DoW @MoY %MoY);
+@DoW = qw(Sun Mon Tue Wed Thu Fri Sat);
+@MoY = qw(Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec);
+@MoY{@MoY} = (1..12);
+
+my %GMT_ZONE = (GMT => 1, UTC => 1, UT => 1, Z => 1);
+
+
+sub time2str (;$)
+{
+ my $time = shift;
+ $time = time unless defined $time;
+ my ($sec, $min, $hour, $mday, $mon, $year, $wday) = gmtime($time);
+ sprintf("%s, %02d %s %04d %02d:%02d:%02d GMT",
+ $DoW[$wday],
+ $mday, $MoY[$mon], $year+1900,
+ $hour, $min, $sec);
+}
+
+
+sub str2time ($;$)
+{
+ my $str = shift;
+ return undef unless defined $str;
+
+ # fast exit for strictly conforming string
+ if ($str =~ /^[SMTWF][a-z][a-z], (\d\d) ([JFMAJSOND][a-z][a-z]) (\d\d\d\d) (\d\d):(\d\d):(\d\d) GMT$/) {
+ return eval {
+ my $t = Time::Local::timegm($6, $5, $4, $1, $MoY{$2}-1, $3);
+ $t < 0 ? undef : $t;
+ };
+ }
+
+ my @d = parse_date($str);
+ return undef unless @d;
+ $d[1]--; # month
+
+ my $tz = pop(@d);
+ unless (defined $tz) {
+ unless (defined($tz = shift)) {
+ return eval { my $frac = $d[-1]; $frac -= ($d[-1] = int($frac));
+ my $t = Time::Local::timelocal(reverse @d) + $frac;
+ $t < 0 ? undef : $t;
+ };
+ }
+ }
+
+ my $offset = 0;
+ if ($GMT_ZONE{uc $tz}) {
+ # offset already zero
+ }
+ elsif ($tz =~ /^([-+])?(\d\d?):?(\d\d)?$/) {
+ $offset = 3600 * $2;
+ $offset += 60 * $3 if $3;
+ $offset *= -1 if $1 && $1 eq '-';
+ }
+ else {
+ eval { require Time::Zone } || return undef;
+ $offset = Time::Zone::tz_offset($tz);
+ return undef unless defined $offset;
+ }
+
+ return eval { my $frac = $d[-1]; $frac -= ($d[-1] = int($frac));
+ my $t = Time::Local::timegm(reverse @d) + $frac;
+ $t < 0 ? undef : $t - $offset;
+ };
+}
+
+
+sub parse_date ($)
+{
+ local($_) = shift;
+ return unless defined;
+
+ # More lax parsing below
+ s/^\s+//; # kill leading space
+ s/^(?:Sun|Mon|Tue|Wed|Thu|Fri|Sat)[a-z]*,?\s*//i; # Useless weekday
+
+ my($day, $mon, $yr, $hr, $min, $sec, $tz, $ampm);
+
+ # Then we are able to check for most of the formats with this regexp
+ (($day,$mon,$yr,$hr,$min,$sec,$tz) =
+ /^
+ (\d\d?) # day
+ (?:\s+|[-\/])
+ (\w+) # month
+ (?:\s+|[-\/])
+ (\d+) # year
+ (?:
+ (?:\s+|:) # separator before clock
+ (\d\d?):(\d\d) # hour:min
+ (?::(\d\d))? # optional seconds
+ )? # optional clock
+ \s*
+ ([-+]?\d{2,4}|(?![APap][Mm]\b)[A-Za-z]+)? # timezone
+ \s*
+ (?:\(\w+\)|\w{3,})? # ASCII representation of timezone.
+ \s*$
+ /x)
+
+ ||
+
+ # Try the ctime and asctime format
+ (($mon, $day, $hr, $min, $sec, $tz, $yr) =
+ /^
+ (\w{1,3}) # month
+ \s+
+ (\d\d?) # day
+ \s+
+ (\d\d?):(\d\d) # hour:min
+ (?::(\d\d))? # optional seconds
+ \s+
+ (?:([A-Za-z]+)\s+)? # optional timezone
+ (\d+) # year
+ \s*$ # allow trailing whitespace
+ /x)
+
+ ||
+
+ # Then the Unix 'ls -l' date format
+ (($mon, $day, $yr, $hr, $min, $sec) =
+ /^
+ (\w{3}) # month
+ \s+
+ (\d\d?) # day
+ \s+
+ (?:
+ (\d\d\d\d) | # year
+ (\d{1,2}):(\d{2}) # hour:min
+ (?::(\d\d))? # optional seconds
+ )
+ \s*$
+ /x)
+
+ ||
+
+ # ISO 8601 format '1996-02-29 12:00:00 -0100' and variants
+ (($yr, $mon, $day, $hr, $min, $sec, $tz) =
+ /^
+ (\d{4}) # year
+ [-\/]?
+ (\d\d?) # numerical month
+ [-\/]?
+ (\d\d?) # day
+ (?:
+ (?:\s+|[-:Tt]) # separator before clock
+ (\d\d?):?(\d\d) # hour:min
+ (?::?(\d\d(?:\.\d*)?))? # optional seconds (and fractional)
+ )? # optional clock
+ \s*
+ ([-+]?\d\d?:?(:?\d\d)?
+ |Z|z)? # timezone (Z is "zero meridian", i.e. GMT)
+ \s*$
+ /x)
+
+ ||
+
+ # Windows 'dir' 11-12-96 03:52PM
+ (($mon, $day, $yr, $hr, $min, $ampm) =
+ /^
+ (\d{2}) # numerical month
+ -
+ (\d{2}) # day
+ -
+ (\d{2}) # year
+ \s+
+ (\d\d?):(\d\d)([APap][Mm]) # hour:min AM or PM
+ \s*$
+ /x)
+
+ ||
+ return; # unrecognized format
+
+ # Translate month name to number
+ $mon = $MoY{$mon} ||
+ $MoY{"\u\L$mon"} ||
+ ($mon =~ /^\d\d?$/ && $mon >= 1 && $mon <= 12 && int($mon)) ||
+ return;
+
+ # If the year is missing, we assume first date before the current,
+ # because of the formats we support such dates are mostly present
+ # on "ls -l" listings.
+ unless (defined $yr) {
+ my $cur_mon;
+ ($cur_mon, $yr) = (localtime)[4, 5];
+ $yr += 1900;
+ $cur_mon++;
+ $yr-- if $mon > $cur_mon;
+ }
+ elsif (length($yr) < 3) {
+ # Find "obvious" year
+ my $cur_yr = (localtime)[5] + 1900;
+ my $m = $cur_yr % 100;
+ my $tmp = $yr;
+ $yr += $cur_yr - $m;
+ $m -= $tmp;
+ $yr += ($m > 0) ? 100 : -100
+ if abs($m) > 50;
+ }
+
+ # Make sure clock elements are defined
+ $hr = 0 unless defined($hr);
+ $min = 0 unless defined($min);
+ $sec = 0 unless defined($sec);
+
+ # Compensate for AM/PM
+ if ($ampm) {
+ $ampm = uc $ampm;
+ $hr = 0 if $hr == 12 && $ampm eq 'AM';
+ $hr += 12 if $ampm eq 'PM' && $hr != 12;
+ }
+
+ return($yr, $mon, $day, $hr, $min, $sec, $tz)
+ if wantarray;
+
+ if (defined $tz) {
+ $tz = "Z" if $tz =~ /^(GMT|UTC?|[-+]?0+)$/;
+ }
+ else {
+ $tz = "";
+ }
+ return sprintf("%04d-%02d-%02d %02d:%02d:%02d%s",
+ $yr, $mon, $day, $hr, $min, $sec, $tz);
+}
+
+
+sub time2iso (;$)
+{
+ my $time = shift;
+ $time = time unless defined $time;
+ my($sec,$min,$hour,$mday,$mon,$year) = localtime($time);
+ sprintf("%04d-%02d-%02d %02d:%02d:%02d",
+ $year+1900, $mon+1, $mday, $hour, $min, $sec);
+}
+
+
+sub time2isoz (;$)
+{
+ my $time = shift;
+ $time = time unless defined $time;
+ my($sec,$min,$hour,$mday,$mon,$year) = gmtime($time);
+ sprintf("%04d-%02d-%02d %02d:%02d:%02dZ",
+ $year+1900, $mon+1, $mday, $hour, $min, $sec);
+}
+
+1;
+
+
+__END__
+
+=head1 NAME
+
+HTTP::Date - date conversion routines
+
+=head1 SYNOPSIS
+
+ use HTTP::Date;
+
+ $string = time2str($time); # Format as GMT ASCII time
+ $time = str2time($string); # convert ASCII date to machine time
+
+=head1 DESCRIPTION
+
+This module provides functions that deal the date formats used by the
+HTTP protocol (and then some more). Only the first two functions,
+time2str() and str2time(), are exported by default.
+
+=over 4
+
+=item time2str( [$time] )
+
+The time2str() function converts a machine time (seconds since epoch)
+to a string. If the function is called without an argument or with an
+undefined argument, it will use the current time.
+
+The string returned is in the format preferred for the HTTP protocol.
+This is a fixed length subset of the format defined by RFC 1123,
+represented in Universal Time (GMT). An example of a time stamp
+in this format is:
+
+ Sun, 06 Nov 1994 08:49:37 GMT
+
+=item str2time( $str [, $zone] )
+
+The str2time() function converts a string to machine time. It returns
+C<undef> if the format of $str is unrecognized, otherwise whatever the
+C<Time::Local> functions can make out of the parsed time. Dates
+before the system's epoch may not work on all operating systems. The
+time formats recognized are the same as for parse_date().
+
+The function also takes an optional second argument that specifies the
+default time zone to use when converting the date. This parameter is
+ignored if the zone is found in the date string itself. If this
+parameter is missing, and the date string format does not contain any
+zone specification, then the local time zone is assumed.
+
+If the zone is not "C<GMT>" or numerical (like "C<-0800>" or
+"C<+0100>"), then the C<Time::Zone> module must be installed in order
+to get the date recognized.
+
+=item parse_date( $str )
+
+This function will try to parse a date string, and then return it as a
+list of numerical values followed by a (possible undefined) time zone
+specifier; ($year, $month, $day, $hour, $min, $sec, $tz). The $year
+will be the full 4-digit year, and $month numbers start with 1 (for January).
+
+In scalar context the numbers are interpolated in a string of the
+"YYYY-MM-DD hh:mm:ss TZ"-format and returned.
+
+If the date is unrecognized, then the empty list is returned (C<undef> in
+scalar context).
+
+The function is able to parse the following formats:
+
+ "Wed, 09 Feb 1994 22:23:32 GMT" -- HTTP format
+ "Thu Feb 3 17:03:55 GMT 1994" -- ctime(3) format
+ "Thu Feb 3 00:00:00 1994", -- ANSI C asctime() format
+ "Tuesday, 08-Feb-94 14:15:29 GMT" -- old rfc850 HTTP format
+ "Tuesday, 08-Feb-1994 14:15:29 GMT" -- broken rfc850 HTTP format
+
+ "03/Feb/1994:17:03:55 -0700" -- common logfile format
+ "09 Feb 1994 22:23:32 GMT" -- HTTP format (no weekday)
+ "08-Feb-94 14:15:29 GMT" -- rfc850 format (no weekday)
+ "08-Feb-1994 14:15:29 GMT" -- broken rfc850 format (no weekday)
+
+ "1994-02-03 14:15:29 -0100" -- ISO 8601 format
+ "1994-02-03 14:15:29" -- zone is optional
+ "1994-02-03" -- only date
+ "1994-02-03T14:15:29" -- Use T as separator
+ "19940203T141529Z" -- ISO 8601 compact format
+ "19940203" -- only date
+
+ "08-Feb-94" -- old rfc850 HTTP format (no weekday, no time)
+ "08-Feb-1994" -- broken rfc850 HTTP format (no weekday, no time)
+ "09 Feb 1994" -- proposed new HTTP format (no weekday, no time)
+ "03/Feb/1994" -- common logfile format (no time, no offset)
+
+ "Feb 3 1994" -- Unix 'ls -l' format
+ "Feb 3 17:03" -- Unix 'ls -l' format
+
+ "11-15-96 03:52PM" -- Windows 'dir' format
+
+The parser ignores leading and trailing whitespace. It also allow the
+seconds to be missing and the month to be numerical in most formats.
+
+If the year is missing, then we assume that the date is the first
+matching date I<before> current month. If the year is given with only
+2 digits, then parse_date() will select the century that makes the
+year closest to the current date.
+
+=item time2iso( [$time] )
+
+Same as time2str(), but returns a "YYYY-MM-DD hh:mm:ss"-formatted
+string representing time in the local time zone.
+
+=item time2isoz( [$time] )
+
+Same as time2str(), but returns a "YYYY-MM-DD hh:mm:ssZ"-formatted
+string representing Universal Time.
+
+
+=back
+
+=head1 SEE ALSO
+
+L<perlfunc/time>, L<Time::Zone>
+
+=head1 COPYRIGHT
+
+Copyright 1995-1999, Gisle Aas
+
+This library is free software; you can redistribute it and/or
+modify it under the same terms as Perl itself.
+
+=cut
diff --git a/t/date.t b/t/date.t
new file mode 100755
index 0000000..129904d
--- /dev/null
+++ b/t/date.t
@@ -0,0 +1,180 @@
+#!perl -w
+
+use strict;
+use Test;
+
+plan tests => 136;
+
+use HTTP::Date;
+
+# test str2time for supported dates. Test cases with 2 digit year
+# will probably break in year 2044.
+my(@tests) =
+(
+ 'Thu Feb 3 00:00:00 GMT 1994', # ctime format
+ 'Thu Feb 3 00:00:00 1994', # same as ctime, except no TZ
+
+ 'Thu, 03 Feb 1994 00:00:00 GMT', # proposed new HTTP format
+ 'Thursday, 03-Feb-94 00:00:00 GMT', # old rfc850 HTTP format
+ 'Thursday, 03-Feb-1994 00:00:00 GMT', # broken rfc850 HTTP format
+
+ '03/Feb/1994:00:00:00 0000', # common logfile format
+ '03/Feb/1994:01:00:00 +0100', # common logfile format
+ '02/Feb/1994:23:00:00 -0100', # common logfile format
+
+ '03 Feb 1994 00:00:00 GMT', # HTTP format (no weekday)
+ '03-Feb-94 00:00:00 GMT', # old rfc850 (no weekday)
+ '03-Feb-1994 00:00:00 GMT', # broken rfc850 (no weekday)
+ '03-Feb-1994 00:00 GMT', # broken rfc850 (no weekday, no seconds)
+ '03-Feb-1994 00:00', # VMS dir listing format
+
+ '03-Feb-94', # old rfc850 HTTP format (no weekday, no time)
+ '03-Feb-1994', # broken rfc850 HTTP format (no weekday, no time)
+ '03 Feb 1994', # proposed new HTTP format (no weekday, no time)
+ '03/Feb/1994', # common logfile format (no time, no offset)
+
+ #'Feb 3 00:00', # Unix 'ls -l' format (can't really test it here)
+ 'Feb 3 1994', # Unix 'ls -l' format
+
+ "02-03-94 12:00AM", # Windows 'dir' format
+
+ # ISO 8601 formats
+ '1994-02-03 00:00:00 +0000',
+ '1994-02-03',
+ '19940203',
+ '1994-02-03T00:00:00+0000',
+ '1994-02-02T23:00:00-0100',
+ '1994-02-02T23:00:00-01:00',
+ '1994-02-03T00:00:00 Z',
+ '19940203T000000Z',
+ '199402030000',
+
+ # A few tests with extra space at various places
+ ' 03/Feb/1994 ',
+ ' 03 Feb 1994 0:00 ',
+
+ # Tests a commonly used (faulty?) date format of php cms systems
+ 'Thu, 03 Feb 1994 00:00:00 +0000 GMT'
+);
+
+my $time = 760233600; # assume broken POSIX counting of seconds
+for (@tests) {
+ my $t;
+ if (/GMT/i) {
+ $t = str2time($_);
+ }
+ else {
+ $t = str2time($_, "GMT");
+ }
+ my $t2 = str2time(lc($_), "GMT");
+ my $t3 = str2time(uc($_), "GMT");
+
+ print "\n# '$_'\n";
+
+ ok($t, $time);
+ ok($t2, $time);
+ ok($t3, $time);
+}
+
+# test time2str
+ok(time2str($time), 'Thu, 03 Feb 1994 00:00:00 GMT');
+
+# test the 'ls -l' format with missing year$
+# round to nearest minute 3 days ago.
+$time = int((time - 3 * 24*60*60) /60)*60;
+my ($min, $hr, $mday, $mon) = (localtime $time)[1,2,3,4];
+$mon = (qw(Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec))[$mon];
+my $str = sprintf("$mon %02d %02d:%02d", $mday, $hr, $min);
+my $t = str2time($str);
+ok($t, $time);
+
+# try some garbage.
+for (undef, '', 'Garbage',
+ 'Mandag 16. September 1996',
+ '12 Arp 2003',
+# 'Thu Feb 3 00:00:00 CET 1994',
+# 'Thu, 03 Feb 1994 00:00:00 CET',
+# 'Wednesday, 31-Dec-69 23:59:59 GMT',
+
+ '1980-00-01',
+ '1980-13-01',
+ '1980-01-00',
+ '1980-01-32',
+ '1980-01-01 25:00:00',
+ '1980-01-01 00:61:00',
+ '1980-01-01 00:00:61',
+ )
+{
+ my $bad = 0;
+ eval {
+ if (defined str2time $_) {
+ print "str2time($_) is not undefined\n";
+ $bad++;
+ }
+ };
+ print defined($_) ? "\n# '$_'\n" : "\n# undef\n";
+ ok(!$@);
+ ok(!$bad);
+}
+
+print "Testing AM/PM gruff...\n";
+
+# Test the str2iso routines
+use HTTP::Date qw(time2iso time2isoz);
+
+print "Testing time2iso functions\n";
+
+$t = time2iso(str2time("11-12-96 0:00AM"));
+ok($t, "1996-11-12 00:00:00");
+
+$t = time2iso(str2time("11-12-96 12:00AM"));
+ok($t, "1996-11-12 00:00:00");
+
+$t = time2iso(str2time("11-12-96 0:00PM"));
+ok($t, "1996-11-12 12:00:00");
+
+$t = time2iso(str2time("11-12-96 12:00PM"));
+ok($t, "1996-11-12 12:00:00");
+
+
+$t = time2iso(str2time("11-12-96 1:05AM"));
+ok($t, "1996-11-12 01:05:00");
+
+$t = time2iso(str2time("11-12-96 12:05AM"));
+ok($t, "1996-11-12 00:05:00");
+
+$t = time2iso(str2time("11-12-96 1:05PM"));
+ok($t, "1996-11-12 13:05:00");
+
+$t = time2iso(str2time("11-12-96 12:05PM"));
+ok($t, "1996-11-12 12:05:00");
+
+$t = str2time("2000-01-01 00:00:01.234");
+print "FRAC $t = ", time2iso($t), "\n";
+ok(abs(($t - int($t)) - 0.234) < 0.000001);
+
+$a = time2iso;
+$b = time2iso(500000);
+print "LOCAL $a $b\n";
+my $az = time2isoz;
+my $bz = time2isoz(500000);
+print "GMT $az $bz\n";
+
+for ($a, $b) { ok(/^\d{4}-\d\d-\d\d \d\d:\d\d:\d\d$/); }
+for ($az, $bz) { ok(/^\d{4}-\d\d-\d\d \d\d:\d\d:\d\dZ$/); }
+
+# Test the parse_date interface
+use HTTP::Date qw(parse_date);
+
+my @d = parse_date("Jan 1 2001");
+
+ok(!defined(pop(@d)));
+ok("@d", "2001 1 1 0 0 0");
+
+# This test will break around year 2070
+ok(parse_date("03-Feb-20"), "2020-02-03 00:00:00");
+
+# This test will break around year 2048
+ok(parse_date("03-Feb-98"), "1998-02-03 00:00:00");
+
+print "HTTP::Date $HTTP::Date::VERSION\n";