]> git.uio.no Git - usit-rt.git/blobdiff - lib/RT/Date.pm
Putting 4.2.0 on top of 4.0.17
[usit-rt.git] / lib / RT / Date.pm
index d3621974ee5096d2120b443dbe11bac331e22020..28a15931a058fa6b9b23db1b261c359599c56502 100644 (file)
@@ -166,10 +166,21 @@ sub Set {
 
     return $self->Unix(0) unless $args{'Value'} && $args{'Value'} =~ /\S/;
 
-    if ( $args{'Format'} =~ /^unix$/i ) {
+    my $format = lc $args{'Format'};
+
+    if ( $format eq 'unix' ) {
         return $self->Unix( $args{'Value'} );
     }
-    elsif ( $args{'Format'} =~ /^(sql|datemanip|iso)$/i ) {
+    elsif (
+        ($format eq 'sql' || $format eq 'iso')
+        && $args{'Value'} =~ /^(\d{4})-(\d\d)-(\d\d) (\d\d):(\d\d):(\d\d)$/
+    ) {
+        local $@;
+        my $u = eval { Time::Local::timegm($6, $5, $4, $3, $2-1, $1) } || 0;
+        $RT::Logger->warning("Invalid date $args{'Value'}: $@") if $@ && !$u;
+        return $self->Unix( $u > 0 ? $u : 0 );
+    }
+    elsif ( $format =~ /^(sql|datemanip|iso)$/ ) {
         $args{'Value'} =~ s!/!-!g;
 
         if (   ( $args{'Value'} =~ /^(\d{4})?(\d\d)(\d\d)(\d\d)(\d\d)(\d\d)$/ )
@@ -201,14 +212,14 @@ sub Set {
             return $self->Unix(0);
         }
     }
-    elsif ( $args{'Format'} =~ /^unknown$/i ) {
+    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 = Time::ParseDate::parsedate(
+        my ($date, $error) = Time::ParseDate::parsedate(
             $args{'Value'},
             GMT           => 1,
             NOW           => $now,
@@ -216,6 +227,13 @@ sub Set {
             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];
 
@@ -223,7 +241,7 @@ sub Set {
             "RT::Date used Time::ParseDate to make '$args{'Value'}' $date\n"
         );
 
-        return $self->Set( Format => 'unix', Value => $date);
+        return $self->Unix($date || 0);
     }
     else {
         $RT::Logger->error(
@@ -323,50 +341,116 @@ sub DiffAsString {
 Takes a number of seconds. Returns a localized string describing
 that duration.
 
+Takes optional named arguments:
+
+=over 4
+
+=item * Show
+
+How many elements to show, how precise it should be. Default is 1,
+most vague variant.
+
+=item * Short
+
+Turn on short notation with one character units, for example
+"3M 2d 1m 10s".
+
+=back
+
 =cut
 
+# loc("[_1]s")
+# loc("[_1]m")
+# loc("[_1]h")
+# loc("[_1]d")
+# loc("[_1]W")
+# loc("[_1]M")
+# loc("[_1]Y")
+# loc("[quant,_1,second]")
+# loc("[quant,_1,minute]")
+# loc("[quant,_1,hour]")
+# loc("[quant,_1,day]")
+# loc("[quant,_1,week]")
+# loc("[quant,_1,month]")
+# loc("[quant,_1,year]")
+
 sub DurationAsString {
     my $self     = shift;
     my $duration = int shift;
+    my %args = ( Show => 1, Short => 0, @_ );
+
+    unless ( $duration ) {
+        return $args{Short}? $self->loc("0s") : $self->loc("0 seconds");
+    }
 
-    my ( $negative, $s, $time_unit );
+    my $negative;
     $negative = 1 if $duration < 0;
     $duration = abs $duration;
 
-    if ( $duration < $MINUTE ) {
-        $s         = $duration;
-        $time_unit = $self->loc("sec");
-    }
-    elsif ( $duration < ( 2 * $HOUR ) ) {
-        $s         = int( $duration / $MINUTE + 0.5 );
-        $time_unit = $self->loc("min");
-    }
-    elsif ( $duration < ( 2 * $DAY ) ) {
-        $s         = int( $duration / $HOUR + 0.5 );
-        $time_unit = $self->loc("hours");
-    }
-    elsif ( $duration < ( 2 * $WEEK ) ) {
-        $s         = int( $duration / $DAY + 0.5 );
-        $time_unit = $self->loc("days");
-    }
-    elsif ( $duration < ( 2 * $MONTH ) ) {
-        $s         = int( $duration / $WEEK + 0.5 );
-        $time_unit = $self->loc("weeks");
-    }
-    elsif ( $duration < $YEAR ) {
-        $s         = int( $duration / $MONTH + 0.5 );
-        $time_unit = $self->loc("months");
-    }
-    else {
-        $s         = int( $duration / $YEAR + 0.5 );
-        $time_unit = $self->loc("years");
+    my %units = (
+        s => 1,
+        m => $MINUTE,
+        h => $HOUR,
+        d => $DAY,
+        W => $WEEK,
+        M => $MONTH,
+        Y => $YEAR,
+    );
+    my %long_units = (
+        s => 'second',
+        m => 'minute',
+        h => 'hour',
+        d => 'day',
+        W => 'week',
+        M => 'month',
+        Y => 'year',
+    );
+
+    my @res;
+
+    my $coef = 2;
+    my $i = 0;
+    while ( $duration > 0 && ++$i <= $args{'Show'} ) {
+
+        my $unit;
+        if ( $duration < $MINUTE ) {
+            $unit = 's';
+        }
+        elsif ( $duration < ( $coef * $HOUR ) ) {
+            $unit = 'm';
+        }
+        elsif ( $duration < ( $coef * $DAY ) ) {
+            $unit = 'h';
+        }
+        elsif ( $duration < ( $coef * $WEEK ) ) {
+            $unit = 'd';
+        }
+        elsif ( $duration < ( $coef * $MONTH ) ) {
+            $unit = 'W';
+        }
+        elsif ( $duration < $YEAR ) {
+            $unit = 'M';
+        }
+        else {
+            $unit = 'Y';
+        }
+        my $value = int( $duration / $units{$unit}  + ($i < $args{'Show'}? 0 : 0.5) );
+        $duration -= int( $value * $units{$unit} );
+
+        if ( $args{'Short'} ) {
+            push @res, $self->loc("[_1]$unit", $value);
+        } else {
+            push @res, $self->loc("[quant,_1,$long_units{$unit}]", $value);
+        }
+
+        $coef = 1;
     }
 
     if ( $negative ) {
-        return $self->loc( "[_1] [_2] ago", $s, $time_unit );
+        return $self->loc( "[_1] ago", join ' ', @res );
     }
     else {
-        return $self->loc( "[_1] [_2]", $s, $time_unit );
+        return join ' ', @res;
     }
 }
 
@@ -620,7 +704,7 @@ sub DefaultFormat
                             $self->Localtime($args{'Timezone'});
     $wday = $self->GetWeekday($wday);
     $mon = $self->GetMonth($mon);
-    ($mday, $hour, $min, $sec) = map { sprintf "%02d", $_ } ($mday, $hour, $min, $sec);
+    $_ = sprintf "%02d", $_ foreach $mday, $hour, $min, $sec;
 
     if( $args{'Date'} && !$args{'Time'} ) {
         return $self->loc('[_1] [_2] [_3] [_4]',
@@ -667,8 +751,8 @@ sub LocaleObj {
 Returns date and time as string, with user localization.
 
 Supports arguments: C<DateFormat> and C<TimeFormat> which may contains date and
-time format as specified in L<DateTime::Locale> (default to full_date_format and
-medium_time_format), C<AbbrDay> and C<AbbrMonth> which may be set to 0 if
+time format as specified in L<DateTime::Locale> (default to C<date_format_full> and
+C<time_format_medium>), C<AbbrDay> and C<AbbrMonth> which may be set to 0 if
 you want full Day/Month names instead of abbreviated ones.
 
 =cut
@@ -888,7 +972,9 @@ sub RFC2616 {
 
 =head4 iCal
 
-Returns the object's date and time in iCalendar format,
+Returns the object's date and time in iCalendar format.
+If only date requested then users timezone is used, otherwise
+it's UTC.
 
 Supports arguments: C<Date> and C<Time>.
 See </Output formatters> for description of arguments.
@@ -901,8 +987,16 @@ sub iCal {
         Date => 1, Time => 1,
         @_,
     );
+
+    my $tz;
+    if ( $args{'Date'} && !$args{'Time'} ) {
+        $tz = 'user';
+    } else {
+        $tz = 'utc';
+    }
+
     my ($sec,$min,$hour,$mday,$mon,$year,$wday,$ydaym,$isdst,$offset) =
-        $self->Localtime( 'utc' );
+        $self->Localtime( $tz );
 
     #the month needs incrementing, as gmtime returns 0-11
     $mon++;
@@ -1053,8 +1147,6 @@ sub Timezone {
 
     my $context = lc(shift);
 
-    $context = 'utc' unless $context =~ /^(?:utc|server|user)$/i;
-
     my $tz;
     if( $context eq 'user' ) {
         $tz = $self->CurrentUser->UserObj->Timezone;