[Rt-commit] rt branch, 4.4/parse-date-with-datetime-format-natural, created. rt-4.2.11-136-ge527517

? sunnavy sunnavy at bestpractical.com
Thu Aug 13 15:09:37 EDT 2015


The branch, 4.4/parse-date-with-datetime-format-natural has been created
        at  e52751759019724d8f77c1bd48d8b8e78d61b6db (commit)

- Log -----------------------------------------------------------------
commit f446755b4e2363d067d9924904aa0579776dff14
Author: sunnavy <sunnavy at bestpractical.com>
Date:   Thu Aug 13 02:10:44 2015 +0800

    abstract date parse by Time::ParseDate into ParseByTimeParseDate
    
    no functions changed.
    we are going to add more date parse methods, this makes things more clear

diff --git a/lib/RT/Date.pm b/lib/RT/Date.pm
index 4344865..282a050 100644
--- a/lib/RT/Date.pm
+++ b/lib/RT/Date.pm
@@ -213,35 +213,7 @@ sub Set {
         }
     }
     elsif ( $format eq 'unknown' ) {
-        require Time::ParseDate;
-        # the module supports only legacy timezones like PDT or EST...
-        # so we parse date as GMT and later apply offset, this only
-        # should be applied to absolute times, so compensate shift in NOW
-        my $now = time;
-        $now += ($self->Localtime( $args{Timezone}, $now ))[9];
-        my ($date, $error) = Time::ParseDate::parsedate(
-            $args{'Value'},
-            GMT           => 1,
-            NOW           => $now,
-            UK            => RT->Config->Get('DateDayBeforeMonth'),
-            PREFER_PAST   => RT->Config->Get('AmbiguousDayInPast'),
-            PREFER_FUTURE => RT->Config->Get('AmbiguousDayInFuture'),
-        );
-        unless ( defined $date ) {
-            $RT::Logger->warning(
-                "Couldn't parse date '$args{'Value'}' by Time::ParseDate"
-            );
-            return $self->Unix(0);
-        }
-
-        # apply timezone offset
-        $date -= ($self->Localtime( $args{Timezone}, $date ))[9];
-
-        $RT::Logger->debug(
-            "RT::Date used Time::ParseDate to make '$args{'Value'}' $date\n"
-        );
-
-        return $self->Unix($date || 0);
+        return $self->Unix($self->ParseByTimeParseDate(%args) || 0);
     }
     else {
         $RT::Logger->error(
@@ -253,6 +225,46 @@ sub Set {
     return $self->Unix;
 }
 
+=head2 ParseByTimeParseDate
+
+Parse date using Time::ParseDate.
+return undef if it fails to parse, otherwise return epoch time.
+
+=cut
+
+sub ParseByTimeParseDate {
+    my $self = shift;
+    my %args = @_;
+    require Time::ParseDate;
+    # the module supports only legacy timezones like PDT or EST...
+    # so we parse date as GMT and later apply offset, this only
+    # should be applied to absolute times, so compensate shift in NOW
+    my $now = time;
+    $now += ($self->Localtime( $args{Timezone}, $now ))[9];
+    my ($date, $error) = Time::ParseDate::parsedate(
+        $args{'Value'},
+        GMT           => 1,
+        NOW           => $now,
+        UK            => RT->Config->Get('DateDayBeforeMonth'),
+        PREFER_PAST   => RT->Config->Get('AmbiguousDayInPast'),
+        PREFER_FUTURE => RT->Config->Get('AmbiguousDayInFuture'),
+    );
+    unless ( defined $date ) {
+        $RT::Logger->warning(
+            "Couldn't parse date '$args{'Value'}' by Time::ParseDate"
+        );
+        return undef;
+    }
+
+    # apply timezone offset
+    $date -= ($self->Localtime( $args{Timezone}, $date ))[9];
+
+    $RT::Logger->debug(
+        "RT::Date used Time::ParseDate to make '$args{'Value'}' $date\n"
+    );
+    return $date;
+}
+
 =head2 SetToNow
 
 Set the object's time to the current time. Takes no arguments

commit e52751759019724d8f77c1bd48d8b8e78d61b6db
Author: sunnavy <sunnavy at bestpractical.com>
Date:   Thu Aug 13 09:16:09 2015 +0800

    enhance date parse with DateTime::Format::Natural
    
    if Time::ParseDate fails to parse, then we will try DateTime::Format::Natural
    
    thanks to DateTime::Format::Natural, Month names are also supported now

diff --git a/lib/RT/Date.pm b/lib/RT/Date.pm
index 282a050..d09411c 100644
--- a/lib/RT/Date.pm
+++ b/lib/RT/Date.pm
@@ -213,7 +213,7 @@ sub Set {
         }
     }
     elsif ( $format eq 'unknown' ) {
-        return $self->Unix($self->ParseByTimeParseDate(%args) || 0);
+        return $self->Unix($self->ParseByTimeParseDate(%args) || $self->ParseByDateTimeFormatNatural(%args) || 0);
     }
     else {
         $RT::Logger->error(
@@ -265,6 +265,38 @@ sub ParseByTimeParseDate {
     return $date;
 }
 
+=head2 ParseByDateTimeFormatNatural
+
+Parse date using DateTime::Format::Natural.
+return undef if it fails to parse, otherwise return epoch time.
+
+=cut
+
+sub ParseByDateTimeFormatNatural {
+    my $self = shift;
+    my %args = @_;
+    require DateTime::Format::Natural;
+
+    my $parser = DateTime::Format::Natural->new(
+        prefer_future => RT->Config->Get('AmbiguousDayInPast') ? 0 : RT->Config->Get('AmbiguousDayInFuture'),
+        time_zone     => $self->Timezone($args{Timezone}),
+    );
+    my ($dt) = eval { $parser->parse_datetime($args{Value}) };
+    if ( !$@ && $parser->success && $dt ) {
+        my $date = $dt->epoch;
+        $RT::Logger->debug(
+            "RT::Date used DateTime::Format::Natural to make '$args{'Value'}' $date\n"
+        );
+        return $date;
+    }
+    else {
+        $RT::Logger->warning(
+            "Couldn't parse date '$args{'Value'}' by DateTime::Format::Natural"
+        );
+        return undef;
+    }
+}
+
 =head2 SetToNow
 
 Set the object's time to the current time. Takes no arguments
diff --git a/t/api/date.t b/t/api/date.t
index dd22943..fd8fce2 100644
--- a/t/api/date.t
+++ b/t/api/date.t
@@ -344,7 +344,9 @@ my $year = (localtime(time))[5] + 1900;
     my $date = RT::Date->new(RT->SystemUser);
     warnings_like {
         $date->Set(Format => 'unknown', Value => 'weird date');
-    } qr{Couldn't parse date 'weird date' by Time::ParseDate};
+    } [ qr{Couldn't parse date 'weird date' by Time::ParseDate},
+        qr{Couldn't parse date 'weird date' by DateTime::Format::Natural}
+      ];
     ok(!$date->IsSet, "date was wrong");
 
     RT->Config->Set( Timezone => 'Europe/Moscow' );
@@ -606,6 +608,36 @@ my $year = (localtime(time))[5] + 1900;
     ok( !$date->IsSet, "unix is 0 with Value => ' ', Format => 'unknown'" );
 }
 
+{
+    # set+unknown format(DateTime::Format::Natural)
+    my $date = RT::Date->new(RT->SystemUser);
+    warnings_like {
+        $date->Set(Format => 'unknown', Value => 'another weird date');
+    } [ qr{Couldn't parse date 'another weird date' by Time::ParseDate},
+        qr{Couldn't parse date 'another weird date' by DateTime::Format::Natural}
+      ], 'warning for "another weird date"';
+    ok(!$date->IsSet, "date was wrong");
+    RT->Config->Set( AmbiguousDayInPast => 0 );
+    RT->Config->Set( AmbiguousDayInFuture => 0 );
+    RT->Config->Set( Timezone => 'Asia/Shanghai' );
+    set_fixed_time("2015-11-28T15:10:00Z");
+    warnings_like {
+        $date->Set(Format => 'unknown', Value => 'Apr');
+    } qr{Couldn't parse date 'Apr' by Time::ParseDate}, "warning by Time::ParseDate";
+    is($date->ISO, '2015-03-31 16:00:00', "April in the past");
+
+    warnings_like {
+        $date->Set(Format => 'unknown', Value => 'Monday');
+    } qr{Couldn't parse date 'Monday' by Time::ParseDate}, "warning by Time::ParseDate";
+    is($date->ISO, '2015-11-22 16:00:00', "Monday in the past");
+
+    RT->Config->Set( AmbiguousDayInFuture => 1 );
+    warnings_like {
+        $date->Set(Format => 'unknown', Value => 'Apr');
+    } qr{Couldn't parse date 'Apr' by Time::ParseDate}, "warning by Time::ParseDate";
+    is($date->ISO, '2016-03-31 16:00:00', "April in the future");
+}
+
 #TODO: AsString
 #TODO: RFC2822, W3CDTF with Timezones
 
diff --git a/t/web/cf_date.t b/t/web/cf_date.t
index 4783484..0b1fe8b 100644
--- a/t/web/cf_date.t
+++ b/t/web/cf_date.t
@@ -187,7 +187,15 @@ diag 'check invalid inputs';
 
     my @warnings = $m->get_warnings;
     chomp @warnings;
-    is_deeply( [@warnings], [(q{Couldn't parse date 'foodate' by Time::ParseDate})x2] );
+    is_deeply(
+        [ @warnings ],
+        [
+            (
+                q{Couldn't parse date 'foodate' by Time::ParseDate},
+                q{Couldn't parse date 'foodate' by DateTime::Format::Natural}
+            ) x 2
+        ]
+    );
 }
 
 diag 'retain values when adding attachments';
diff --git a/t/web/cf_datetime.t b/t/web/cf_datetime.t
index a370ce4..5ec2885 100644
--- a/t/web/cf_datetime.t
+++ b/t/web/cf_datetime.t
@@ -213,7 +213,15 @@ diag 'check invalid inputs';
 
     my @warnings = $m->get_warnings;
     chomp @warnings;
-    is_deeply( [@warnings], [(q{Couldn't parse date 'foodate' by Time::ParseDate})x2] );
+    is_deeply(
+        [ @warnings ],
+        [
+            (
+                q{Couldn't parse date 'foodate' by Time::ParseDate},
+                q{Couldn't parse date 'foodate' by DateTime::Format::Natural}
+            ) x 2
+        ]
+    );
 }
 
 diag 'retain values when adding attachments';
diff --git a/t/web/ticket_modify_all.t b/t/web/ticket_modify_all.t
index 6b85d98..3563048 100644
--- a/t/web/ticket_modify_all.t
+++ b/t/web/ticket_modify_all.t
@@ -63,7 +63,20 @@ for my $unset ("0", "-", " ") {
     $m->field('Due_Date' => $unset);
     $m->click('SubmitTicket');
     $m->text_contains("Due: (Not set)", "due date successfully cleared with '$unset'");
-    $m->warning_like(qr/Couldn't parse date '-'/) if $unset eq "-";
+
+    if ( $unset eq '-' ) {
+        my @warnings = $m->get_warnings;
+        chomp @warnings;
+        is_deeply(
+            [ @warnings ],
+            [
+                (
+                    q{Couldn't parse date '-' by Time::ParseDate},
+                    q{Couldn't parse date '-' by DateTime::Format::Natural}
+                )
+            ]
+        );
+    }
 }
 
 $m->get( $url . '/Ticket/ModifyAll.html?id=' . $ticket->id );

-----------------------------------------------------------------------


More information about the rt-commit mailing list