# BEGIN BPS TAGGED BLOCK {{{
-#
+#
# COPYRIGHT:
-#
-# This software is Copyright (c) 1996-2009 Best Practical Solutions, LLC
-# <jesse@bestpractical.com>
-#
+#
+# This software is Copyright (c) 1996-2012 Best Practical Solutions, LLC
+# <sales@bestpractical.com>
+#
# (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
# 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
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;
);
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
@_
);
- 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'} );
return $self->Unix( $new );
}
+=head2 SetToStart PERIOD[, Timezone => 'utc' ]
+
+Set to the beginning of the current PERIOD, which can be
+"year", "month", "day", "hour", or "minute".
+
+=cut
+
+sub SetToStart {
+ my $self = shift;
+ my $p = uc(shift);
+ 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.
+ {
+ $localtime[0]=0;
+ last if ($p eq 'MINUTE');
+ $localtime[1]=0;
+ last if ($p eq 'HOUR');
+ $localtime[2]=0;
+ last if ($p eq 'DAY');
+ $localtime[3]=1;
+ last if ($p eq 'MONTH');
+ $localtime[4]=0;
+ last if ($p eq 'YEAR');
+ $RT::Logger->warning("Couldn't find start date of '$p'.");
+ return;
+ }
+ my $new = $self->Timelocal($tz, @localtime);
+ return $self->Unix($new);
+}
+
=head2 Diff
Takes either an C<RT::Date> object or the date in unixtime format as a string,
sub AddDay { return $_[0]->AddSeconds($DAY) }
+=head2 AddMonth
+
+Adds one month to the current time. Returns new
+unix time.
+
+=cut
+
+sub AddMonth {
+ my $self = shift;
+ 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]
Optionally takes a date in unix seconds since the epoch format.
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 );
}
return @FORMATTERS;
}
+=head3 ValidFormatter FORMAT
+
+Returns a true value if C<FORMAT> 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
}
}
+=head2 LocaleObj
+
+Returns the L<DateTime::Locale> 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<DateFormat> and C<TimeFormat> which may contains date and
-time format as specified in DateTime::Locale (default to full_date_format 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
you want full Day/Month names instead of abbreviated ones.
-Require optionnal DateTime::Locale module.
-
=cut
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');
-
+ # Require valid names for the format methods
+ my $date_format = $args{DateFormat} =~ /^\w+$/
+ ? $args{DateFormat} : 'date_format_full';
- my $date_format = $args{'DateFormat'};
- my $time_format = $args{'TimeFormat'};
-
- 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'} );
# 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,
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;
}
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;
}
-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;