These do the following:
Change all tabs to spaces.
Add support for parsing and generating dates with fractional seconds.
Add support for parsing time zones with seconds (which the generator
was capable of generating).
Add a test for parsing dates with fractional seconds.
diff -ru DateTime-Format-W3CDTF-0.04/lib/DateTime/Format/W3CDTF.pm DateTime-Format-W3CDTF-Fixed/lib/DateTime/Format/W3CDTF.pm
--- DateTime-Format-W3CDTF-0.04/lib/DateTime/Format/W3CDTF.pm 2003-11-23 21:09:56.000000000 -0500
+++ DateTime-Format-W3CDTF-Fixed/lib/DateTime/Format/W3CDTF.pm 2005-08-29 11:08:46.000000000 -0400
@@ -7,6 +7,7 @@
$VERSION = '0.04';
use DateTime;
+use DateTime::TimeZone;
sub new
{
@@ -15,92 +16,69 @@
return bless {}, $class;
}
-# key is string length
-my %valid_formats =
- ( 19 =>
- { params => [ qw( year month day hour minute second) ],
- regex => qr/^(\d{4})-(\d\d)-(\d\d)T(\d\d):(\d\d):(\d\d)$/,
- zero => {},
- },
- 16 =>
- { params => [ qw( year month day hour minute) ],
- regex => qr/^(\d{4})-(\d\d)-(\d\d)T(\d\d):(\d\d)$/,
- zero => { second => 0 },
- },
- 10 =>
- { params => [ qw( year month day ) ],
- regex => qr/^(\d{4})-(\d\d)-(\d\d)$/,
- zero => { hour => 0, minute => 0, second => 0 },
- },
- 7 =>
- { params => [ qw( year month ) ],
- regex => qr/^(\d{4})-(\d\d)$/,
- zero => { day => 1, hour => 0, minute => 0, second => 0 },
- },
- 4 =>
- { params => [ qw( year ) ],
- regex => qr/^(\d\d\d\d)$/,
- zero => { month => 1, day => 1, hour => 0, minute => 0, second => 0 }
- }
- );
-
sub parse_datetime
{
my ( $self, $date ) = @_;
- # save for error messages
- my $original = $date;
-
- my %p;
- if ( $date =~ s/([+-]\d\d:\d\d)$// )
- {
- $p{time_zone} = $1;
+ my @fields = qw/ year month day hour minute second fraction time_zone /;
+ my @values =
+ ( $date =~ /^(\d\d\d\d) # Year
+ (?:-(\d\d) # -Month
+ (?:-(\d\d) # -Day
+ (?:T
+ (\d\d):(\d\d) # Hour:Minute
+ (?:
+ :(\d\d) # :Second
+ (\.\d+)? # .Fractional_Second
+ )?
+ ( Z # UTC
+ | [+-]\d\d:\d\d # Hour:Minute TZ offset
+ (?::\d\d)? # :Second TZ offset
+ )?)?)?)?$/x )
+ or die "Invalid W3CDTF datetime string ($date)";
+ my %p;
+ for ( my $i=0; $i < @values; $i++ ) { # Oh how I wish Perl had zip
+ next unless defined $values[$i];
+ $p{$fields[$i]} = $values[$i];
}
- # Z at end means UTC
- elsif ( $date =~ s/Z$// )
- {
- $p{time_zone} = 'UTC';
+ if ( !$p{time_zone} ) {
+ $p{time_zone} = 'floating';
}
- else
+ elsif ( $p{time_zone} eq 'Z' )
{
- $p{time_zone} = 'floating';
+ $p{time_zone} = 'UTC';
}
- my $format = $valid_formats{ length $date }
- or die "Invalid W3CDTF datetime string ($original)";
-
- @p{ @{ $format->{params} } } = $date =~ /$format->{regex}/;
+ if ( $p{fraction} ) {
+ $p{nanosecond} = $p{fraction} * 1_000_000_000;
+ delete $p{fraction}
+ }
- return DateTime->new( %p, %{ $format->{zero} } );
+ return DateTime->new( %p );
}
sub format_datetime
{
my ( $self, $dt ) = @_;
- # removed in 0.4 as it behaved improperly at midnight - kellan 2003/11/23
- #my $base =
- # ( $dt->hour || $dt->min || $dt->sec ?
- # sprintf( '%04d-%02d-%02dT%02d:%02d:%02d',
- # $dt->year, $dt->month, $dt->day,
- # $dt->hour, $dt->minute, $dt->second ) :
- # sprintf( '%04d-%02d-%02d', $dt->year, $dt->month, $dt->day )
- # );
-
- my $base = sprintf( '%04d-%02d-%02dT%02d:%02d:%02d',
- $dt->year, $dt->month, $dt->day,
+ my $base = sprintf( '%04d-%02d-%02dT%02d:%02d:%02d',
+ $dt->year, $dt->month, $dt->day,
$dt->hour, $dt->minute, $dt->second );
-
+ if ( $dt->nanosecond ) {
+ my $secs = sprintf "%f", $dt->nanosecond / 1_000_000_000;
+ $secs =~ s/^0//;
+ $base .= $secs;
+ }
my $tz = $dt->time_zone;
return $base if $tz->is_floating;
- return $base . 'Z' if $tz->is_utc;
+ return $base . 'Z' if $tz->is_utc;
- if (my $offset = $dt->offset()) {
- return $base . offset_as_string($offset );
- }
+ if (my $offset = $dt->offset()) {
+ return $base . offset_as_string( $offset );
+ }
}
sub format_date
@@ -108,7 +86,7 @@
my ( $self, $dt ) = @_;
my $base = sprintf( '%04d-%02d-%02d', $dt->year, $dt->month, $dt->day );
- return $base;
+ return $base;
}
# minor offset_as_string variant w/ :
diff -ru DateTime-Format-W3CDTF-0.04/t/01parse.t DateTime-Format-W3CDTF-Fixed/t/01parse.t
--- DateTime-Format-W3CDTF-0.04/t/01parse.t 2003-11-23 21:09:56.000000000 -0500
+++ DateTime-Format-W3CDTF-Fixed/t/01parse.t 2005-08-29 11:07:37.000000000 -0400
@@ -1,5 +1,5 @@
#!/usr/bin/perl -w
-use Test::More tests => 17;
+use Test::More tests => 18;
use strict;
use vars qw( $class );
@@ -9,15 +9,16 @@
}
my @tests = (
- '2003-02-10T15:23:45' => '2003-02-10T15:23:45',
- '1997-04-11T09:34' => '1997-04-11T09:34:00',
- '2002-05-12' => '2002-05-12T00:00:00',
- '1985-06' => '1985-06-01T00:00:00',
- '1988' => '1988-01-01T00:00:00',
- # '2001-02-30' => '2001-03-02T00:00:00',
- '2005-03-10T20:14:34+09:30' => '2005-03-10T10:44:34',
- '2000-06-12T14:12:33Z' => '2000-06-12T14:12:33',
- '1994-11-05T08:15:30-05:00' => '1994-11-05T13:15:30',
+ '2003-02-10T15:23:45' => '2003-02-10T15:23:45',
+ '1997-04-11T09:34' => '1997-04-11T09:34:00',
+ '2002-05-12' => '2002-05-12T00:00:00',
+ '1985-06' => '1985-06-01T00:00:00',
+ '1988' => '1988-01-01T00:00:00',
+ # '2001-02-30' => '2001-03-02T00:00:00',
+ '2005-03-10T20:14:34+09:30' => '2005-03-10T10:44:34',
+ '2000-06-12T14:12:33Z' => '2000-06-12T14:12:33',
+ '1994-11-05T08:15:30-05:00' => '1994-11-05T13:15:30',
+ '2004-07-01T15:00:13.17-05:00' => '2004-07-01T20:00:13',
);
while (@tests)
diff -ru DateTime-Format-W3CDTF-0.04/t/02bugs.t DateTime-Format-W3CDTF-Fixed/t/02bugs.t
--- DateTime-Format-W3CDTF-0.04/t/02bugs.t 2003-11-23 21:09:56.000000000 -0500
+++ DateTime-Format-W3CDTF-Fixed/t/02bugs.t 2005-08-29 11:08:30.000000000 -0400
@@ -1,7 +1,7 @@
#!/usr/bin/perl -w
# test bug 3766
-#
http://rt.cpan.org/NoAuth/Bug.html?id=3766
+#
http://rt.cpan.org/NoAuth/Bug.html?id=3766
# returns undef when you pass it a DateTime object
# whose timezone has been explicitly set.
@@ -17,26 +17,26 @@
use DateTime::Format::W3CDTF;
my @dates = (
- { date => { year => 1977, month => 11, day => 11, hour => 1, minute => 12, time_zone => 'America/Los_Angeles' },
- w3cdtf => '1977-11-11T01:12:00-08:00',
- msg => 'formatter works with explicit timezone',
- },
- { date => { year => 1977, month => 4, day => 7, time_zone => 'America/Los_Angeles' },
- w3cdtf => '1977-04-07T00:00:00-08:00',
- msg => 'formatter works without timestamp',
- },
- { date => { year => 2003, month => 4, day => 7, hour => 2, time_zone => 'America/Los_Angeles' },
- w3cdtf => '2003-04-07T02:00:00-07:00',
- msg => 'formatter properly recognizing daylights saving'
- },
- { date => { year => 2003, month => 12, day => 25, hour => 0, minute => 00, second => 00, time_zone => 'America/Montreal' },
- w3cdtf => '2003-12-25T00:00:00-05:00',
- msg => 'formatter properly formats midnight'
- }
+ { date => { year => 1977, month => 11, day => 11, hour => 1, minute => 12, time_zone => 'America/Los_Angeles' },
+ w3cdtf => '1977-11-11T01:12:00-08:00',
+ msg => 'formatter works with explicit timezone',
+ },
+ { date => { year => 1977, month => 4, day => 7, time_zone => 'America/Los_Angeles' },
+ w3cdtf => '1977-04-07T00:00:00-08:00',
+ msg => 'formatter works without timestamp',
+ },
+ { date => { year => 2003, month => 4, day => 7, hour => 2, time_zone => 'America/Los_Angeles' },
+ w3cdtf => '2003-04-07T02:00:00-07:00',
+ msg => 'formatter properly recognizing daylights saving'
+ },
+ { date => { year => 2003, month => 12, day => 25, hour => 0, minute => 00, second => 00, time_zone => 'America/Montreal' },
+ w3cdtf => '2003-12-25T00:00:00-05:00',
+ msg => 'formatter properly formats midnight'
+ }
);
my $f = DateTime::Format::W3CDTF->new();
foreach my $d ( @dates ) {
- my $dt = DateTime->new( %{ $d->{date} } );
- is ( $f->format_datetime($dt), $d->{w3cdtf}, $d->{msg});
-}
\ No newline at end of file
+ my $dt = DateTime->new( %{ $d->{date} } );
+ is ( $f->format_datetime($dt), $d->{w3cdtf}, $d->{msg});
+}