Bivio::Type::Date
# Copyright (c) 1999-2010 bivio Software, Inc. All rights reserved.
# $Id$
package Bivio::Type::Date;
use strict;
use Bivio::Base 'Type.DateTime';
# C<Bivio::Type::Date> describes a date value which cannot have does not have a
# time component. C<Date> is stored in the database as an SQL C<DATE> whose
# clock componentis 21:59:59 (GMT). In perl, a date is represented as
# julian days and seconds on that day ('J SSSSS').
my($_DT) = b_use('Type.DateTime');
my($_DEFAULT_TIME) = __PACKAGE__->DEFAULT_TIME;
my($_MIN) = _to(__PACKAGE__, __PACKAGE__->FIRST_DATE_IN_JULIAN_DAYS);
my($_MAX) = _to(__PACKAGE__, __PACKAGE__->LAST_DATE_IN_JULIAN_DAYS);
#TODO: Assumes we are in the US.
my($_NOW_SLOP) = 9 * 60 * 60;
sub REGEX_FILE_NAME {
return qr{(\d{4})(\d{2})(\d{2})};
}
sub TO_STRING_REGEX {
return qr{(\d+/\d+/\d+)};
}
sub can_be_zero {
return 0;
}
sub delta_days {
my($proto, $start_date, $end_date) = @_;
return ($proto->internal_split($end_date))[0]
- ($proto->internal_split($start_date))[0];
}
sub delta_months {
my($proto, $start_date, $end_date) = @_;
return -$proto->delta_months($end_date, $start_date)
if $proto->compare($start_date, $end_date) > 0;
my(undef, undef, undef, $start_day, $start_month, $start_year)
= $proto->to_parts($start_date);
my(undef, undef, undef, $end_day, $end_month, $end_year)
= $proto->to_parts($end_date);
my($months) = 12 * ($end_year - $start_year)
+ ($end_month - $start_month);
$months--
if $start_day > $end_day;
return $months;
}
sub from_datetime {
my($proto, $date_time) = @_;
my($date, $time) = $proto->internal_split($date_time);
my($v, $e) = $proto->SUPER::from_literal(_to($proto, $date));
return ($v, $e)
if $e;
return $v;
}
sub from_literal {
my($proto, $value) = @_;
$proto->internal_from_literal_warning
unless wantarray;
return undef
unless defined($value) && $value =~ /\S/;
return _from_date_time($proto, $value, $1)
if $value =~ /^\d+ (\d+)$/;
$value =~ s/\s+//g;
return $proto->date_from_parts($3, $2, $1)
if $value =~ m{^(\d{4})[/-](\d+)[/-](\d+)$}s;
return $proto->date_from_parts($2, $1, $3)
if $value =~ m{^(\d+)[/-](\d+)[/-](\d{4})$}s;
return $proto->date_from_parts($3, $2, $1)
if $value =~ m{^(\d{4})(\d{2})(\d{2})$}s;
return $proto->date_from_parts(
$1,
$proto->english_month3_to_int($2),
$3,
) if $value =~ m{^(\d+)-([a-z]{3})-(\d{4})$}is;
return $proto->date_from_parts($1, $2, $3)
if $value =~ m{^(\d+)\.(\d+)\.(\d{4})$}s;
return (undef, Bivio::TypeError->DATE);
}
sub from_sql_column {
my($proto) = shift;
my($value) = $proto->SUPER::from_sql_column(@_);
b_die($value, ': invalid date in database (clock component)')
if defined($value) && $value !~ /$_DEFAULT_TIME$/o;
return $value;
}
sub from_unix {
my($proto) = shift;
return $proto->from_datetime($proto->SUPER::from_unix(@_));
}
sub get_default {
my($self) = @_;
return $self->now;
}
sub get_max {
return $_MAX;
}
sub get_min {
return $_MIN;
}
sub get_width {
return 10;
}
sub local_today {
my($proto) = @_;
return _to(
$proto,
($proto->internal_split(
$proto->add_seconds($proto->SUPER::now, -$proto->timezone * 60),
))[0],
);
}
sub local_yesterday {
my($proto) = @_;
return $proto->add_days($proto->local_today, -1);
}
sub now {
my($proto) = @_;
return $proto->from_datetime($proto->SUPER::now);
}
sub to_file_name {
my($proto, $value) = @_;
my($sec, $min, $hour, $day, $mon, $year) = $proto->to_parts($value);
return sprintf('%04d%02d%02d', $year, $mon, $day);
}
sub to_literal {
my($proto, $value) = @_;
return shift->SUPER::to_literal(@_)
unless defined($value);
my(undef, undef, undef, $d, $m, $y) = $proto->to_parts($value);
return sprintf('%02d/%02d/%04d', $m, $d, $y);
}
sub to_sql_param {
my(undef, $param_value) = @_;
return undef
unless defined($param_value);
b_die($param_value, ': invalid date (clock component)')
unless $param_value =~ /$_DEFAULT_TIME$/o;
return $param_value;
}
sub to_string {
return shift->to_literal(@_);
}
sub to_xml {
my($proto, $value) = @_;
# Converts to a XSL date (see
# http://www.w3.org/TR/xmlschema-2/#date).
# See also ISO 8601 (see http://www.iso.ch/markete/8601.pdf).
return ''
unless defined($value);
my(undef, undef, undef, $mday, $mon, $year) = $proto->to_parts($value);
return sprintf('%04d-%02d-%02d', $year, $mon, $mday);
}
sub _from_date_time {
my($proto, $value, $time) = @_;
my($v, $e) = $proto->SUPER::from_literal($value);
return ($v, $e)
if $e;
return (undef, Bivio::TypeError->TIME_COMPONENT_OF_DATE)
unless $time eq $_DEFAULT_TIME;
return $v;
}
sub _to {
my($proto, $julian) = @_;
return $proto->internal_join($julian, $_DEFAULT_TIME);
}
1;