X-Git-Url: http://git.freeside.biz/gitweb/?a=blobdiff_plain;f=rt%2Flib%2FRT%2FDate.pm;h=52bdc01dfe1416309efc42ff82380cca8cadfe55;hb=0ea23112cfa0d82738b0f08d60d90579721b7524;hp=2c7a6b66fb771a4aa45dfe48caaf36f433ea5c02;hpb=ca5ea1f2105485d640cc68f99954b683de997561;p=freeside.git diff --git a/rt/lib/RT/Date.pm b/rt/lib/RT/Date.pm index 2c7a6b66f..52bdc01df 100644 --- a/rt/lib/RT/Date.pm +++ b/rt/lib/RT/Date.pm @@ -1,40 +1,40 @@ # BEGIN BPS TAGGED BLOCK {{{ -# +# # COPYRIGHT: -# -# This software is Copyright (c) 1996-2009 Best Practical Solutions, LLC -# -# +# +# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC +# +# # (Except where explicitly superseded by other copyright notices) -# -# +# +# # LICENSE: -# +# # This work is made available to you under the terms of Version 2 of # the GNU General Public License. A copy of that license should have # been provided with this software, but in any event can be snarfed # from www.gnu.org. -# +# # This work is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. -# +# # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA # 02110-1301 or visit their web page on the internet at # http://www.gnu.org/licenses/old-licenses/gpl-2.0.html. -# -# +# +# # CONTRIBUTION SUBMISSION POLICY: -# +# # (The following paragraph is not intended to limit the rights granted # to you to modify and distribute this software under the terms of # the GNU General Public License and is only of importance to you if # you choose to contribute your changes and enhancements to the # community by submitting them to Best Practical Solutions, LLC.) -# +# # By intentionally submitting any modifications, corrections or # derivatives to this work, or any other work intended for use with # Request Tracker, to Best Practical Solutions, LLC, you confirm that @@ -43,7 +43,7 @@ # royalty-free, perpetual, license to use, copy, create derivative # works based on those contributions, and sublicense and distribute # those contributions and any derivatives thereof. -# +# # END BPS TAGGED BLOCK }}} =head1 NAME @@ -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,7 +164,7 @@ sub Set { @_ ); - return $self->Unix(0) unless $args{'Value'}; + return $self->Unix(0) unless $args{'Value'} && $args{'Value'} =~ /\S/; if ( $args{'Format'} =~ /^unix$/i ) { return $self->Unix( $args{'Value'} ); @@ -208,7 +208,7 @@ sub Set { # 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 +216,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]; @@ -286,6 +293,8 @@ sub SetToStart { my %args = @_; my $tz = $args{'Timezone'} || ''; my @localtime = $self->Localtime($tz); + #remove 'offset' so that DST is figured based on the resulting time. + pop @localtime; # This is the cleanest way to implement it, I swear. { @@ -500,7 +509,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 ); } @@ -519,16 +529,21 @@ unix time. =cut -sub AddMonth { - require Time::ParseDate; +sub AddMonth { my $self = shift; - my $date = ( - Time::ParseDate::parsedate( - '1 month', - NOW => $self->Unix - ) - ); - return $self->Unix($date); + my %args = @_; + my @localtime = $self->Localtime($args{'Timezone'}); + # remove offset, as with SetToStart + pop @localtime; + + $localtime[4]++; #month + if ( $localtime[4] == 12 ) { + $localtime[4] = 0; + $localtime[5]++; #year + } + + my $new = $self->Timelocal($args{'Timezone'}, @localtime); + return $self->Unix($new); } =head2 Unix [unixtime] @@ -597,6 +612,10 @@ sub Get my $self = shift; my %args = (Format => 'ISO', @_); my $formatter = $args{'Format'}; + unless ( $self->ValidFormatter($formatter) ) { + RT->Logger->warning("Invalid date formatter '$formatter', falling back to ISO"); + $formatter = 'ISO'; + } $formatter = 'ISO' unless $self->can($formatter); return $self->$formatter( %args ); } @@ -635,6 +654,20 @@ sub Formatters return @FORMATTERS; } +=head3 ValidFormatter FORMAT + +Returns a true value if C is a known formatter. Otherwise returns +false. + +=cut + +sub ValidFormatter { + my $self = shift; + my $format = shift; + return (grep { $_ eq $format } $self->Formatters and $self->can($format)) + ? 1 : 0; +} + =head3 DefaultFormat =cut @@ -678,17 +711,33 @@ sub DefaultFormat } } +=head2 LocaleObj + +Returns the L object representing the current user's locale. + +=cut + +sub LocaleObj { + my $self = shift; + + my $lang = $self->CurrentUser->UserObj->Lang; + unless ($lang) { + require I18N::LangTags::Detect; + $lang = ( I18N::LangTags::Detect::detect(), 'en' )[0]; + } + + return DateTime::Locale->load($lang); +} + =head3 LocalizedDateTime Returns date and time as string, with user localization. Supports arguments: C and C which may contains date and -time format as specified in DateTime::Locale (default to full_date_format and +time format as specified in L (default to full_date_format and medium_time_format), C and C which may be set to 0 if you want full Day/Month names instead of abbreviated ones. -Require optionnal DateTime::Locale module. - =cut sub LocalizedDateTime @@ -697,32 +746,21 @@ sub LocalizedDateTime my %args = ( Date => 1, Time => 1, Timezone => '', - DateFormat => 'date_format_full', - TimeFormat => 'time_format_medium', + DateFormat => '', + TimeFormat => '', AbbrDay => 1, AbbrMonth => 1, @_, ); - return $self->loc("DateTime module missing") unless ( eval 'use DateTime qw(); 1;' ); - return $self->loc("DateTime::Locale module missing") unless ( eval 'use DateTime::Locale qw(); 1;' ); - return $self->loc("DateTime doesn't support format_cldr, you must upgrade to use this feature") - unless can DateTime::('format_cldr'); - - - my $date_format = $args{'DateFormat'}; - my $time_format = $args{'TimeFormat'}; + # Require valid names for the format methods + my $date_format = $args{DateFormat} =~ /^\w+$/ + ? $args{DateFormat} : 'date_format_full'; - my $lang = $self->CurrentUser->UserObj->Lang; - unless ($lang) { - require I18N::LangTags::Detect; - $lang = ( I18N::LangTags::Detect::detect(), 'en' )[0]; - } - + my $time_format = $args{TimeFormat} =~ /^\w+$/ + ? $args{TimeFormat} : 'time_format_medium'; - my $formatter = DateTime::Locale->load($lang); - return $self->loc("DateTime::Locale doesn't support date_format_full, you must upgrade to use this feature") - unless $formatter->can('date_format_full'); + my $formatter = $self->LocaleObj; $date_format = $formatter->$date_format; $time_format = $formatter->$time_format; $date_format =~ s/EEEE/EEE/g if ( $args{'AbbrDay'} ); @@ -735,7 +773,7 @@ sub LocalizedDateTime # FIXME : another way to call this module without conflict with local # DateTime method? - my $dt = new DateTime::( locale => $lang, + my $dt = DateTime::->new( locale => $formatter, time_zone => $tz, year => $year, month => $mon, @@ -865,7 +903,7 @@ sub RFC2822 { my ($date, $time) = ('',''); $date .= "$DAYS_OF_WEEK[$wday], " if $args{'DayOfWeek'} && $args{'Date'}; - $date .= "$mday $MONTHS[$mon] $year" if $args{'Date'}; + $date .= sprintf("%02d %s %04d", $mday, $MONTHS[$mon], $year) if $args{'Date'}; if ( $args{'Time'} ) { $time .= sprintf("%02d:%02d", $hour, $min); @@ -910,7 +948,7 @@ sub RFC2616 { Seconds => 1, DayOfWeek => 1, ); - my $res = $self->RFC2822( @_ ); + my $res = $self->RFC2822( %args ); $res =~ s/\s*[+-]\d\d\d\d$/ GMT/ if $args{'Time'}; return $res; } @@ -930,21 +968,20 @@ sub iCal { Date => 1, Time => 1, @_, ); - my ($sec,$min,$hour,$mday,$mon,$year,$wday,$ydaym,$isdst,$offset) = - $self->Localtime( 'utc' ); - - #the month needs incrementing, as gmtime returns 0-11 - $mon++; my $res; if ( $args{'Date'} && !$args{'Time'} ) { - $res = sprintf( '%04d%02d%02d', $year, $mon, $mday ); - } - elsif ( !$args{'Date'} && $args{'Time'} ) { + my (undef, undef, undef, $mday, $mon, $year) = + $self->Localtime( 'user' ); + $res = sprintf( '%04d%02d%02d', $year, $mon+1, $mday ); + } elsif ( !$args{'Date'} && $args{'Time'} ) { + my ($sec, $min, $hour) = + $self->Localtime( 'utc' ); $res = sprintf( 'T%02d%02d%02dZ', $hour, $min, $sec ); - } - else { - $res = sprintf( '%04d%02d%02dT%02d%02d%02dZ', $year, $mon, $mday, $hour, $min, $sec ); + } else { + my ($sec, $min, $hour, $mday, $mon, $year) = + $self->Localtime( 'utc' ); + $res = sprintf( '%04d%02d%02dT%02d%02d%02dZ', $year, $mon+1, $mday, $hour, $min, $sec ); } return $res; } @@ -1074,6 +1111,12 @@ If both server's and user's timezone names are undefined returns 'UTC'. sub Timezone { my $self = shift; + + if (@_ == 0) { + Carp::carp "RT::Date->Timezone is a setter only"; + return undef; + } + my $context = lc(shift); $context = 'utc' unless $context =~ /^(?:utc|server|user)$/i; @@ -1092,9 +1135,6 @@ sub Timezone { } -eval "require RT::Date_Vendor"; -die $@ if ($@ && $@ !~ qr{^Can't locate RT/Date_Vendor.pm}); -eval "require RT::Date_Local"; -die $@ if ($@ && $@ !~ qr{^Can't locate RT/Date_Local.pm}); +RT::Base->_ImportOverlays(); 1;