X-Git-Url: http://git.freeside.biz/gitweb/?p=freeside.git;a=blobdiff_plain;f=rt%2Flib%2FRT%2FDate.pm;h=c572b757996e1f73517cec7bb5a8d9501e155b6b;hp=e68526c075dbea5061511b58d2ad43bda9aab474;hb=f2731f7f3883905cd17633f486d2aeb9593173da;hpb=b5c4237a34aef94976bc343c8d9e138664fc3984 diff --git a/rt/lib/RT/Date.pm b/rt/lib/RT/Date.pm index e68526c07..c572b7579 100644 --- a/rt/lib/RT/Date.pm +++ b/rt/lib/RT/Date.pm @@ -2,7 +2,7 @@ # # COPYRIGHT: # -# This software is Copyright (c) 1996-2011 Best Practical Solutions, LLC +# This software is Copyright (c) 1996-2015 Best Practical Solutions, LLC # # # (Except where explicitly superseded by other copyright notices) @@ -56,7 +56,7 @@ =head1 DESCRIPTION -RT Date is a simple Date Object designed to be speedy and easy for RT to use +RT Date is a simple Date Object designed to be speedy and easy for RT to use. The fact that it assumes that a time of 0 means "never" is probably a bug. @@ -68,13 +68,16 @@ The fact that it assumes that a time of 0 means "never" is probably a bug. package RT::Date; -use Time::Local; -use POSIX qw(tzset); use strict; use warnings; + use base qw/RT::Base/; +use DateTime; + +use Time::Local; +use POSIX qw(tzset); use vars qw($MINUTE $HOUR $DAY $WEEK $MONTH $YEAR); $MINUTE = 60; @@ -110,17 +113,14 @@ our @DAYS_OF_WEEK = ( ); our @FORMATTERS = ( - 'DefaultFormat', # loc - 'ISO', # loc - 'W3CDTF', # loc - 'RFC2822', # loc - 'RFC2616', # loc - 'iCal', # loc + 'DefaultFormat', # loc + 'ISO', # loc + 'W3CDTF', # loc + 'RFC2822', # loc + 'RFC2616', # loc + 'iCal', # loc + 'LocalizedDateTime', # loc ); -if ( eval 'use DateTime qw(); 1;' && eval 'use DateTime::Locale qw(); 1;' && - DateTime->can('format_cldr') && DateTime::Locale::root->can('date_format_full') ) { - push @FORMATTERS, 'LocalizedDateTime'; # loc -} =head2 new @@ -164,12 +164,23 @@ sub Set { @_ ); - return $self->Unix(0) unless $args{'Value'}; + 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( @@ -358,56 +376,105 @@ 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 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 @res; + + my $coef = 2; + my $i = 0; + while ( $duration > 0 && ++$i <= $args{'Show'} ) { + + my ($locstr, $unit); + if ( $duration < $MINUTE ) { + $locstr = $args{Short} + ? '[_1]s' # loc + : '[quant,_1,second,seconds]'; # loc + $unit = 1; + } + elsif ( $duration < ( $coef * $HOUR ) ) { + $locstr = $args{Short} + ? '[_1]m' # loc + : '[quant,_1,minute,minutes]'; # loc + $unit = $MINUTE; + } + elsif ( $duration < ( $coef * $DAY ) ) { + $locstr = $args{Short} + ? '[_1]h' # loc + : '[quant,_1,hour,hours]'; # loc + $unit = $HOUR; + } + elsif ( $duration < ( $coef * $WEEK ) ) { + $locstr = $args{Short} + ? '[_1]d' # loc + : '[quant,_1,day,days]'; # loc + $unit = $DAY; + } + elsif ( $duration < ( $coef * $MONTH ) ) { + $locstr = $args{Short} + ? '[_1]W' # loc + : '[quant,_1,week,weeks]'; # loc + $unit = $WEEK; + } + elsif ( $duration < $YEAR ) { + $locstr = $args{Short} + ? '[_1]M' # loc + : '[quant,_1,month,months]'; # loc + $unit = $MONTH; + } + else { + $locstr = $args{Short} + ? '[_1]Y' # loc + : '[quant,_1,year,years]'; # loc + $unit = $YEAR; + } + my $value = int( $duration / $unit + ($i < $args{'Show'}? 0 : 0.5) ); + $duration -= int( $value * $unit ); + + push @res, $self->loc($locstr, $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; } } =head2 AgeAsString -Takes nothing. Returns a string that's the differnce between the +Takes nothing. Returns a string that's the difference between the time in the object and now. =cut @@ -418,10 +485,10 @@ sub AgeAsString { return $_[0]->DiffAsString } =head2 AsString -Returns the object's time as a localized string with curent user's prefered +Returns the object's time as a localized string with curent user's preferred format and timezone. -If the current user didn't choose prefered format then system wide setting is +If the current user didn't choose preferred format then system wide setting is used or L if the latter is not specified. See config option C. @@ -431,7 +498,7 @@ sub AsString { my $self = shift; my %args = (@_); - return $self->loc("Not set") unless $self->Unix > 0; + return $self->loc("Not set") unless $self->IsSet; my $format = RT->Config->Get( 'DateTimeFormat', $self->CurrentUser ) || 'DefaultFormat'; $format = { Format => $format } unless ref $format; @@ -502,7 +569,8 @@ Returns new unix time. sub AddDays { my $self = shift; - my $days = shift || 1; + my $days = shift; + $days = 1 unless defined $days; return $self->AddSeconds( $days * $DAY ); } @@ -547,13 +615,21 @@ Returns the number of seconds since the epoch sub Unix { my $self = shift; - $self->{'time'} = int(shift || 0) if @_; + + if (@_) { + my $time = int(shift || 0); + if ($time < 0) { + RT->Logger->notice("Passed a unix time less than 0, forcing to 0: [$time]"); + $time = 0; + } + $self->{'time'} = int $time; + } return $self->{'time'}; } =head2 DateTime -Alias for L method. Arguments C and