Bivio::Type::DateInterval
# Copyright (c) 2000-2010 bivio Software, Inc. All rights reserved.
# $Id$
package Bivio::Type::DateInterval;
use strict;
use Bivio::Base 'Type.Enum';
my($_DT) = b_use('Type.DateTime');
__PACKAGE__->compile([
NONE => [
0,
],
DAY => [
1,
],
WEEK => [
7,
],
MONTH => [
-1,
],
YEAR => [
-2,
],
FISCAL_YEAR => [
-3,
],
SIX_MONTHS => [
-4,
],
THREE_MONTHS => [
-5,
],
IRS_TAX_SEASON => [
-6,
],
]);
sub dec {
# (self, string) : string
# Returns I<date_time> decremented by this DateInterval.
my($self, $date_time) = @_;
return $self->as_int >= 0 ? $_DT->add_days($date_time, -$self->as_int)
: &{\&{'_dec_'.lc($self->get_name)}}($date_time);
}
sub inc {
# (self, string) : string
# Returns I<date_time> incremented by this DateInterval.
my($self, $date_time) = @_;
return $self->as_int >= 0 ? $_DT->add_days($date_time, $self->as_int)
: &{\&{'_inc_'.lc($self->get_name)}}($date_time);
}
sub inc_to_end {
# (self, string) : string
# Increments I<start_date> to end of interval. It does not adjust the time
# component. For DAY and NONE is no-op. For YEAR, WEEK, and MONTH increments by
# the amount and substracts one day. It does not go to the calendar period
# except for FISCAL_YEAR, e.g. MONTH-E<gt>inc_to_end('12/22/2001') is
# 1/21/2001 (not 12/31/2001).
#
# FISCAL_YEAR increments to 12/31.
my($self, $start_date) = @_;
my($sub) = \&{'_inc_to_end_'.lc($self->get_name)};
return defined(&$sub) ? $sub->($self, $start_date)
: $_DT->add_days($self->inc($start_date), -1);
}
sub is_continuous {
# (self) : boolean
# Returns false.
return 0;
}
sub _dec_fiscal_year {
# (string) : string
# On 1/1, goes to prior year. Else, goes to beginning of this year.
my($date_time) = @_;
my($sec, $min, $hour, $mday, $mon, $year) = $_DT->to_parts($date_time);
$year--
if $mday == 1 && $mon == 1;
return $_DT->from_parts_or_die($sec, $min, $hour, 1, 1, $year);
}
sub _dec_irs_tax_season {
# (string) : string
# If on or before 4/15, goes to 1/1 prior year. Else, goes to 1/1 of this
# year.
my($date_time) = @_;
my($sec, $min, $hour, $mday, $mon, $year) = $_DT->to_parts($date_time);
$year--
if $mon < 4 || $mon == 4 && $mday <= 15;
return $_DT->from_parts_or_die($sec, $min, $hour, 1, 1, $year);
}
sub _dec_month {
# (string) : string
# Goes to same date/time in previous month. Goes to end of month if outside
# of month boundary.
my($date_time) = @_;
my($sec, $min, $hour, $mday, $mon, $year)
= $_DT->to_parts($date_time);
$mon = $mon == 1 ? ($year--, 12) : $mon - 1;
return _from_parts_with_mday_correction($sec, $min, $hour,
$mday, $mon, $year);
}
sub _dec_six_months {
# (string) : string
# Decrement six months.
return $_DT->add_months(shift, -6);
}
sub _dec_three_months {
# (string) : string
# Decrement three months.
return $_DT->add_months(shift, -3);
}
sub _dec_year {
# (string) : string
# Goes to same date/time in previous year. Goes to month of year if outside
# of month boundary.
my($date_time) = @_;
my($sec, $min, $hour, $mday, $mon, $year)
= $_DT->to_parts($date_time);
return _from_parts_with_mday_correction($sec, $min, $hour,
$mday, $mon, $year - 1);
}
sub _from_parts_with_mday_correction {
# (int, int, int, int, int, int) : string
# Returns DateTime->from_parts correcting mday to be at month's end
# if not already at month's end.
my($sec, $min, $hour, $mday, $mon, $year) = @_;
my($last) = $_DT->get_last_day_in_month($mon, $year);
return $_DT->from_parts_or_die($sec, $min, $hour,
$mday > $last ? $last : $mday, $mon, $year);
}
sub _inc_fiscal_year {
# (string) : string
# Goes to beginning of next year.
my($date_time) = @_;
my($sec, $min, $hour, $mday, $mon, $year)
= $_DT->to_parts($date_time);
return $_DT->from_parts_or_die($sec, $min, $hour, 1, 1, 1 + $year);
}
sub _inc_irs_tax_season {
# (string) : string
# Goes to the beginning of next year (just like fiscal year)
return _inc_fiscal_year(@_);
}
sub _inc_month {
# (string) : string
# Goes to same date/time next month. Goes to end of month if outside
# of month boundary.
my($date_time) = @_;
my($sec, $min, $hour, $mday, $mon, $year)
= $_DT->to_parts($date_time);
$mon = $mon == 12 ? ($year++, 1) : $mon + 1;
return _from_parts_with_mday_correction($sec, $min, $hour,
$mday, $mon, $year);
}
sub _inc_six_months {
# (string) : string
# Increments by six months.
return $_DT->add_months(shift, 6);
}
sub _inc_three_months {
# (string) : string
# Increments by three months.
return $_DT->add_months(shift, 3);
}
sub _inc_to_end_day {
# (self, string) : string
# No-op.
shift;
return shift;
}
sub _inc_to_end_irs_tax_season {
# (self, string) : string
# Goes to 4/15 of this year if at or before 4/15.
my($self, $start_date) = @_;
my($sec, $min, $hour, $mday, $mon, $year) = $_DT->to_parts($start_date);
return $_DT->from_parts_or_die($sec, $min, $hour, 15, 4, ++$year);
}
sub _inc_to_end_none {
# (self, string) : string
# No-op.
shift;
return shift;
}
sub _inc_year {
# (string) : string
# Goes to same date/time in previous year. Goes to month of year if outside
# of month boundary.
my($date_time) = @_;
my($sec, $min, $hour, $mday, $mon, $year)
= $_DT->to_parts($date_time);
return _from_parts_with_mday_correction($sec, $min, $hour,
$mday, $mon, $year + 1);
}
1;