X-Git-Url: http://git.rot13.org/?a=blobdiff_plain;f=Koha%2FDateUtils.pm;h=51d3d93a75bb0757341af5148bba16e08fd3014c;hb=5833673157d75ba6fbf2caedf7931283b4eabf7d;hp=a1fd088fe45790ca212379278ed15d82ed550e4e;hpb=5432bd488f2cd842f4fece93c42423a3fc26143b;p=koha.git diff --git a/Koha/DateUtils.pm b/Koha/DateUtils.pm index a1fd088fe4..51d3d93a75 100644 --- a/Koha/DateUtils.pm +++ b/Koha/DateUtils.pm @@ -13,21 +13,18 @@ package Koha::DateUtils; # 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 -# Koha; if not, write to the Free Software Foundation, Inc., 59 Temple Place, -# Suite 330, Boston, MA 02111-1307 USA +# Koha; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -use strict; -use warnings; -use 5.010; +use Modern::Perl; use DateTime; -use DateTime::Format::DateParse; use C4::Context; +use Carp; use base 'Exporter'; -use version; our $VERSION = qv('1.0.0'); our @EXPORT = ( - qw( dt_from_string output_pref format_sqldatetime output_pref_due format_sqlduedatetime) + qw( dt_from_string output_pref format_sqldatetime ) ); =head1 DateUtils @@ -53,95 +50,223 @@ to the system preferences. If the date string is empty DateTime->now is returned sub dt_from_string { my ( $date_string, $date_format, $tz ) = @_; - if ( !$tz ) { - $tz = C4::Context->tz; - } - if ( !$date_format ) { - $date_format = C4::Context->preference('dateformat'); - } - if ($date_string) { - if ( ref($date_string) eq 'DateTime' ) { # already a dt return it - return $date_string; - } - - if ( $date_format eq 'metric' ) { - $date_string =~ s#-#/#g; - $date_string =~ s/^00/01/; # system allows the 0th of the month - $date_string =~ s#^(\d{1,2})/(\d{1,2})#$2/$1#; - } else { - if ( $date_format eq 'iso' ) { - $date_string =~ s/-00/-01/; - if ( $date_string =~ m/^0000-0/ ) { - return; # invalid date in db - } - } elsif ( $date_format eq 'us' ) { - $date_string =~ s#-#/#g; - $date_string =~ s[/00/][/01/]; - } elsif ( $date_format eq 'sql' ) { - $date_string =~ -s/(\d{4})(\d{2})(\d{2})\s+(\d{2})(\d{2})(\d{2})/$1-$2-$3T$4:$5:$6/; - $date_string =~ s/00T/01T/; - } - } - return DateTime::Format::DateParse->parse_datetime( $date_string, - $tz->name() ); - } - return DateTime->now( time_zone => $tz ); + return if $date_string and $date_string =~ m|^0000-0|; + + $tz = C4::Context->tz unless $tz;; + + return DateTime->now( time_zone => $tz ) unless $date_string; + + $date_format = C4::Context->preference('dateformat') unless $date_format; + + if ( ref($date_string) eq 'DateTime' ) { # already a dt return it + return $date_string; + } + + my $regex; + + # The fallback format is sql/iso + my $fallback_re = qr| + (?\d{4}) + - + (?\d{2}) + - + (?\d{2}) + |xms; + + if ( $date_format eq 'metric' ) { + # metric format is "dd/mm/yyyy[ hh:mm:ss]" + $regex = qr| + (?\d{2}) + / + (?\d{2}) + / + (?\d{4}) + |xms; + } + elsif ( $date_format eq 'dmydot' ) { + # dmydot format is "dd.mm.yyyy[ hh:mm:ss]" + $regex = qr| + (?\d{2}) + . + (?\d{2}) + . + (?\d{4}) + |xms; + } + elsif ( $date_format eq 'us' ) { + # us format is "mm/dd/yyyy[ hh:mm:ss]" + $regex = qr| + (?\d{2}) + / + (?\d{2}) + / + (?\d{4}) + |xms; + } + elsif ( $date_format eq 'iso' or $date_format eq 'sql' ) { + # iso or sql format are yyyy-dd-mm[ hh:mm:ss]" + $regex = $fallback_re; + } + else { + die "Invalid dateformat parameter ($date_format)"; + } + + # Add the faculative time part [hh:mm[:ss]] + my $time_re .= qr| + ( + \s* + (?\d{2}) + : + (?\d{2}) + ( + : + (?\d{2}) + )? + )? + |xms; + $regex .= $time_re; + $fallback_re .= $time_re; + + my %dt_params; + if ( $date_string =~ $regex ) { + %dt_params = ( + year => $+{year}, + month => $+{month}, + day => $+{day}, + hour => $+{hour}, + minute => $+{minute}, + second => $+{second}, + ); + } elsif ( $date_string =~ $fallback_re ) { + %dt_params = ( + year => $+{year}, + month => $+{month}, + day => $+{day}, + hour => $+{hour}, + minute => $+{minute}, + second => $+{second}, + ); + } + else { + die "The given date ($date_string) does not match the date format ($date_format)"; + } + + # system allows the 0th of the month + $dt_params{day} = '01' if $dt_params{day} eq '00'; + + # Set default hh:mm:ss to 00:00:00 + $dt_params{hour} = 00 unless defined $dt_params{hour}; + $dt_params{minute} = 00 unless defined $dt_params{minute}; + $dt_params{second} = 00 unless defined $dt_params{second}; + + my $dt = eval { + DateTime->new( + %dt_params, + # No TZ for dates 'infinite' => see bug 13242 + ( $dt_params{year} < 9999 ? ( time_zone => $tz->name ) : () ), + ); + }; + if ($@) { + $tz = DateTime::TimeZone->new( name => 'floating' ); + $dt = DateTime->new( + %dt_params, + # No TZ for dates 'infinite' => see bug 13242 + ( $dt_params{year} < 9999 ? ( time_zone => $tz->name ) : () ), + ); + } + return $dt; } =head2 output_pref -$date_string = output_pref($dt, [$format] ); +$date_string = output_pref({ dt => $dt [, dateformat => $date_format, timeformat => $time_format, dateonly => 0|1, as_due_date => 0|1 ] }); +$date_string = output_pref( $dt ); -Returns a string containing the time & date formatted as per the C4::Context setting +Returns a string containing the time & date formatted as per the C4::Context setting, +or C if C was provided. -A second parameter allows overriding of the syspref value. This is for testing only -In usage use the DateTime objects own methods for non standard formatting +This routine can either be passed a DateTime object or or a hashref. If it is +passed a hashref, the expected keys are a mandatory 'dt' for the DateTime, +an optional 'dateformat' to override the dateformat system preference, an +optional 'timeformat' to override the TimeFormat system preference value, +and an optional 'dateonly' to specify that only the formatted date string +should be returned without the time. =cut sub output_pref { - my $dt = shift; - my $force_pref = shift; # if testing we want to override Context - my $pref = - defined $force_pref ? $force_pref : C4::Context->preference('dateformat'); - given ($pref) { - when (/^iso/) { - return $dt->strftime('%Y-%m-%d %H:%M'); - } - when (/^metric/) { - return $dt->strftime('%d/%m/%Y %H:%M'); - } - when (/^us/) { - return $dt->strftime('%m/%d/%Y %H:%M'); - } - default { - return $dt->strftime('%Y-%m-%d %H:%M'); - } - - } - return; -} + my $params = shift; + my ( $dt, $str, $force_pref, $force_time, $dateonly, $as_due_date ); + if ( ref $params eq 'HASH' ) { + $dt = $params->{dt}; + $str = $params->{str}; + $force_pref = $params->{dateformat}; # if testing we want to override Context + $force_time = $params->{timeformat}; + $dateonly = $params->{dateonly} || 0; # if you don't want the hours and minutes + $as_due_date = $params->{as_due_date} || 0; # don't display the hours and minutes if eq to 23:59 or 11:59 (depending the TimeFormat value) + } else { + $dt = $params; + } -=head2 output_pref_due + carp "output_pref should not be called with both dt and str parameters" + and return + if $dt and $str; -$date_string = output_pref_due($dt, [$format] ); + if ( $str ) { + local $@; + $dt = eval { dt_from_string( $str ) }; + carp "Invalid date '$str' passed to output_pref\n" if $@; + } -Returns a string containing the time & date formatted as per the C4::Context setting + return unless defined $dt; -A second parameter allows overriding of the syspref value. This is for testing only -In usage use the DateTime objects own methods for non standard formatting + # FIXME: see bug 13242 => no TZ for dates 'infinite' + if ( $dt->ymd !~ /^9999/ ) { + my $tz = $dateonly ? DateTime::TimeZone->new(name => 'floating') : C4::Context->tz; + $dt->set_time_zone( $tz ); + } -This is effectivelyt a wrapper around output_pref for due dates -the time portion is stripped if it is '23:59' + my $pref = + defined $force_pref ? $force_pref : C4::Context->preference('dateformat'); -=cut + my $time_format = $force_time || C4::Context->preference('TimeFormat') || q{}; + my $time = ( $time_format eq '12hr' ) ? '%I:%M %p' : '%H:%M'; + my $date; + if ( $pref =~ m/^iso/ ) { + $date = $dateonly + ? $dt->strftime("%Y-%m-%d") + : $dt->strftime("%Y-%m-%d $time"); + } + elsif ( $pref =~ m/^metric/ ) { + $date = $dateonly + ? $dt->strftime("%d/%m/%Y") + : $dt->strftime("%d/%m/%Y $time"); + } + elsif ( $pref =~ m/^dmydot/ ) { + $date = $dateonly + ? $dt->strftime("%d.%m.%Y") + : $dt->strftime("%d.%m.%Y $time"); + } + + elsif ( $pref =~ m/^us/ ) { + $date = $dateonly + ? $dt->strftime("%m/%d/%Y") + : $dt->strftime("%m/%d/%Y $time"); + } + else { + $date = $dateonly + ? $dt->strftime("%Y-%m-%d") + : $dt->strftime("%Y-%m-%d $time"); + } + + if ( $as_due_date ) { + $time_format eq '12hr' + ? $date =~ s| 11:59 PM$|| + : $date =~ s| 23:59$||; + } -sub output_pref_due { - my $disp_str = output_pref(@_); - $disp_str =~ s/ 23:59//; - return $disp_str; + return $date; } =head2 format_sqldatetime @@ -156,30 +281,19 @@ with output_pref as it is a frequent activity in scripts sub format_sqldatetime { my $str = shift; my $force_pref = shift; # if testing we want to override Context - if ( defined $str && $str =~ m/^\d{4}-\d{2}-\d{2}/ ) { - my $dt = dt_from_string( $str, 'sql' ); - $dt->truncate( to => 'minute' ); - return output_pref( $dt, $force_pref ); - } - return q{}; -} - -=head2 format_sqlduedatetime - -$string = format_sqldatetime( $string_as_returned_from_db ); + my $force_time = shift; + my $dateonly = shift; -a convenience routine for calling dt_from_string and formatting the result -with output_pref_due as it is a frequent activity in scripts - -=cut - -sub format_sqlduedatetime { - my $str = shift; - my $force_pref = shift; # if testing we want to override Context if ( defined $str && $str =~ m/^\d{4}-\d{2}-\d{2}/ ) { my $dt = dt_from_string( $str, 'sql' ); + return q{} unless $dt; $dt->truncate( to => 'minute' ); - return output_pref_due( $dt, $force_pref ); + return output_pref({ + dt => $dt, + dateformat => $force_pref, + timeformat => $force_time, + dateonly => $dateonly + }); } return q{}; }