Solstice::DateTime - Models a point in time.


Solstice documentation Contained in the Solstice distribution.

Index


Code Index:

NAME

Top

Solstice::DateTime - Models a point in time.

SYNOPSIS

Top

  use Solstice::DateTime;

  my $dt = new Solstice::DateTime(time());
  my $dt = new Solstice::DateTime('2005-03-11 02:34:12');
  my $dt = new Solstice::DateTime('now');

  # These functions return the object
  $date_time->addYears($year_count);
  $date_time->addMonths($month_count);
  $date_time->addDays($day_count);

DESCRIPTION

Top

Export

No symbols exported.

Methods

new([$input])

Constructor. Returns a DateTime object.

setDate($year, $month, $day)

Sets the date

setTime($hour, $min, $sec [, $ampm])

Sets the time

clone()

Returns a duplicate DateTime object.

addYears($years)

Add some number of years to the date.

addMonths($months)

Add some number of months to the date.

addDays($days)

Add some number of days to the date

addHours($hours)

Add some number of hours to the date

addMinutes($min)

Add some number of min to the date

addSeconds($sec)

Add some number of seconds to the date

getYear()
getMonth()
getDay()
getHour()
getMin()
getSec()
isValidDate()

Validate the date values as forming a valid date. Date::Calc::check_date does the heavy work.

isValidTime()

Validate the time values as forming a valid time. Date::Calc::check_time does the heavy work.

isValid()

Returns a boolean specifying whether the obj datetime is valid

isEmpty()

Returns a boolean specifying whether the obj contains a datetime

isEqualTo($datetime)

Returns a boolean specifying whether the obj datetime is equal to the passed datetime.

isSameDay($datetime)

Returns a boolean specifying whether the obj datetime is the same date to the passed in datetime

isBefore($datetime)

Returns a boolean specifying whether the obj datetime is before the passed datetime.

isBeforeNow()

Returns a boolean specifying whether the obj datetime is before now.

getDaysApart($datetime)

Returns the number of days apart the 2 datetime objects are, as a float. Returns 0 if either is invalid.

getTimeApart($datetime)

Returns the number of seconds apart the 2 datetime objects are. Returns 0 if either is invalid.

toSQL()

Returns an SQL formatted date

toISO()

Returns an ISO 8601 formatted date

toCommon()

Returns a human-readable date string

toMovingWindow()

Return a formatted string, that displays a moving 3-day window

toUnix()

Returns a Unix formatted date (epoch seconds)

toString($format)

Returns a formatted datetime string; $format contains a strftime-style formatting string. Date validity is not implicit.

cmpDate($date)

Takes a date object and compares it to itself.

Private Methods

_init($input)
_addYMD($y, $m, $d)

Does the heavy lifting for addDays, addMonths, and addYears.

_updateToNow()

Update the date if the DateTime obj is a 'now' obj

Private Functions

_getAccessorDefinition()

Modules Used

Date::Format.

AUTHOR

Top

Catalyst Group, <catalyst@u.washington.edu>

VERSION

Top

$Revision: 3364 $

COPYRIGHT

Top


Solstice documentation Contained in the Solstice distribution.
package Solstice::DateTime;

# $Id: DateTime.pm 3364 2006-05-05 07:18:21Z mcrawfor $

use 5.006_000;
use strict;
use warnings;

use base qw(Solstice::Model);

use Date::Calc qw(:all);
use Date::Format;

use constant TRUE    => 1;
use constant FALSE   => 0;
use constant SUCCESS => 1;
use constant FAIL    => 0;

our ($VERSION) = ('$Revision: 3364 $' =~ /^\$Revision:\s*([\d.]*)/);

sub new {
    my $class = shift;
    my $input = shift;
    
    my $self = $class->SUPER::new();

    return $self unless defined $input;

    $self->_init($input);

    return $self;
}

sub setDate {
    my $self = shift;
    my ($year, $month, $day) = @_;

    $self->_setYear($year);
    $self->_setMonth($month);
    $self->_setDay($day);
    return SUCCESS; 
}    

sub setTime {
    my $self = shift;
    my ($hour, $min, $sec, $ampm) = @_;

    if (defined $ampm and defined $hour and $hour =~ /^\d+$/) {
        $hour += 12 if ($ampm eq 'pm' and $hour > 0 and $hour < 13);
        $hour = 0 if ($ampm eq 'am' and $hour == 12);
    }

    $self->_setHour($hour);
    $self->_setMin($min);
    $self->_setSec($sec);
    return SUCCESS;
}

sub clone {
    my $self = shift;
    $self->_updateToNow();
    
    my $clone = Solstice::DateTime->new({
        year   => $self->_getYear(),
        month  => $self->_getMonth(),
        day    => $self->_getDay(),
        hour   => $self->_getHour(),
        min    => $self->_getMin(),
        sec    => $self->_getSec(),
        ampm   => 0,
    });
    $clone->setIsNow($self->getIsNow());
    
    return $clone;
}

sub addYears {
    my $self = shift;
    my $years = shift;
    return $self->_addYMD($years, 0, 0);
}

sub addMonths {
    my $self = shift;
    my $months = shift;
    return $self->_addYMD(0, $months, 0);
}

sub addDays {
    my $self = shift;
    my $days = shift;
    return $self->_addYMD(0, 0, $days);
}

sub addHours {
    my $self = shift;
    my $hours = shift;
    return $self->_addHMS($hours, 0, 0);
}

sub addMinutes {
    my $self = shift;
    my $min = shift;
    return $self->_addHMS(0, $min, 0);
}

sub addSeconds {
    my $self = shift;
    my $seconds = shift;
    return $self->_addHMS(0, 0, $seconds);
}

sub getYear {
    my $self = shift;
    $self->_updateToNow();
    return $self->_getYear();
}

    
sub getMonth {
    my $self = shift;
    $self->_updateToNow();
    return $self->_getMonth();
}

           
sub getDay {
    my $self = shift;
    $self->_updateToNow();
    return $self->_getDay();
}

sub getHour {
    my $self = shift;
    $self->_updateToNow();
    return $self->_getHour();
}

sub getMin {
    my $self = shift;
    $self->_updateToNow();
    return $self->_getMin();
}

sub getSec {
    my $self = shift;
    $self->_updateToNow();
    return $self->_getSec();
}

sub isValidDate {
    my $self = shift;
    
    return TRUE if $self->getIsNow();
    
    my $year  = $self->_getYear();
    my $month = $self->_getMonth();
    my $day   = $self->_getDay();

    return FALSE unless (
        defined $year and $year =~ /^\d+$/ and 
        defined $month and $month =~ /^\d+$/ and
        defined $day and $day =~ /^\d+$/
    );
    
    return check_date($year, $month, $day) ? TRUE : FALSE;
}

sub isValidTime {
    my $self = shift;

    return TRUE if $self->getIsNow();
    
    my $hour = $self->_getHour();
    my $min  = $self->_getMin();
    my $sec  = $self->_getSec();

    return FALSE unless (
        defined $hour and $hour =~ /^\d+$/ and
        defined $min and $min =~ /^\d+$/ and
        defined $sec and $sec =~ /^\d+$/
    );
    
    return check_time($hour, $min, $sec) ? TRUE : FALSE;
}

sub isValid {
    my $self = shift;
    return ($self->isValidDate() && $self->isValidTime()) ? TRUE : FALSE;
}

sub isEmpty {
    my $self = shift;

    return FALSE if $self->getIsNow();
    
    return ($self->_getYear() || $self->_getMonth() || $self->_getDay() || $self->_getHour() || $self->_getMin() || $self->_getSec()) ? FALSE : TRUE;
}

sub isEqualTo {
    my $self = shift;
    my $arg  = shift;

    return FALSE unless $self->isValid();
    return FALSE unless (defined $arg and $arg->isValid());

    $self->_updateToNow();
    $arg->_updateToNow();

    return ($self->getTimeApart($arg)==0) ? TRUE : FALSE;
}

sub isSameDay {
    my $self = shift;
    my $arg = shift;

    return FALSE unless $self->isValid();
    return FALSE unless (defined $arg && $arg->isValid());

    $self->_updateToNow();
    $arg->_updateToNow();

    return ($self->getDaysApart($arg)==0) ? TRUE : FALSE;
}
    
sub isBefore {
    my $self = shift;
    my $arg  = shift;

    return undef unless $self->isValid();
    return undef unless (defined $arg and $arg->isValid());

    $self->_updateToNow();
    $arg->_updateToNow();
    my $days1 = Date_to_Days($self->_getYear(), $self->_getMonth(), $self->_getDay());
    my $days2 = Date_to_Days($arg->_getYear(), $arg->_getMonth(), $arg->_getDay());

    return TRUE if ($days1 < $days2);
    return FALSE if ($days1 > $days2);
    return ($self->_getHour() * 3600 + $self->_getMin() * 60 + $self->_getSec()) <
        ($arg->_getHour() * 3600 + $arg->_getMin() * 60 + $arg->_getSec()) ? TRUE : FALSE;
}

sub isBeforeNow {
    my $self = shift;
    
    return undef unless $self->isValid();
    return FALSE if $self->getIsNow();

    $self->_updateToNow();
    my ($year, $month, $day, $hour, $min, $sec) = Today_and_Now();

    my $days1 = Date_to_Days($self->_getYear(), $self->_getMonth(), $self->_getDay());
    my $days2 = Date_to_Days($year, $month, $day);

    return TRUE if ($days1 < $days2);
    return FALSE if ($days1 > $days2);
    return ($self->_getHour() * 3600 + $self->_getMin() * 60 + $self->_getSec()) <
        ($hour * 3600 + $min * 60 + $sec) ? TRUE : FALSE;    
}


sub getDaysApart {
    my $self = shift;
    my $date = shift;

    return 0 unless $self->isValidDate();
    return 0 unless $date->isValidDate();

    return Delta_Days($self->getYear(), $self->getMonth(), $self->getDay(), $date->getYear(), $date->getMonth(), $date->getDay());
}

sub getTimeApart {
    my $self = shift;
    my $date = shift;
    
    return 0 unless $self->isValidDate();
    return 0 unless $date->isValidDate();

    my ($day, $hour, $min, $sec) = 
                    Delta_DHMS($self->getYear(), $self->getMonth(), $self->getDay(),$self->getHour(), $self->getMin(),$self->getSec(), 
                    $date->getYear(), $date->getMonth(), $date->getDay(), $date->getHour(), $date->getMin(), $date->getSec());
    
    return $sec +($min*60)+($hour*3600)+ ($day*24*3600);
}

sub toSQL {
    my $self = shift;
    
    return undef unless $self->isValid();

    return $self->toString("%Y-%m-%d %H:%M:%S");
}

sub toISO {
    my $self = shift;

    return undef unless $self->isValid();

    return $self->toString("%Y%m%d%H%M%S");
}

sub toCommon {
    my $self = shift;

    return undef unless $self->isValid();

    return $self->toString("%L/%d/%Y %l:%M %p");
}

sub toMovingWindow {
    my $self = shift;

    return undef unless $self->isValid();

    my $now = time();
    my $day = 60 * 60 * 24;
    my $dateformat = "%L%d%Y";
    my $timeformat = "%l:%M %p";
    
    my $date = $self->toString($dateformat);
    if($self->isBefore(Solstice::DateTime->new($now - $day)) || Solstice::DateTime->new($now + $day)->isBefore($self)){
        return $self->toString("%b %e, %Y %l:%M %p");
    }
    elsif ($date == Solstice::DateTime->new($now)->toString($dateformat)) {
        return $self->toString('Today, '.$timeformat);
    } elsif ($date == Solstice::DateTime->new($now - $day)->toString($dateformat)) {
        return $self->toString('Yesterday, '.$timeformat);
    } elsif ($date == Solstice::DateTime->new($now + $day)->toString($dateformat)) {
        return $self->toString('Tomorrow, '.$timeformat);
    }else {
        return $self->toString("%b %e, %Y %l:%M %p");
    }
}

sub toUnix {
    my $self = shift;


    # seeing as 3:14:07 a.m. on Jan. 19, 2038 is the limit on 32bit machines for unix timestamps
    # we don't want to be using this method since our model considers dates larger than that valid
    warn "toUnix is deprecated!! DO NOT USE AT ". join(' ', caller());

    return undef unless $self->isValid();

    $self->_updateToNow();
    return Mktime($self->_getYear(), $self->_getMonth(), $self->_getDay(),
        $self->_getHour(), $self->_getMin(), $self->_getSec());
}

sub toString {
    my $self = shift;
    my $format = shift;
    
    $self->_updateToNow();
    my @date  = ($self->_getSec(), $self->_getMin(), $self->_getHour(),
        $self->_getDay(), ($self->_getMonth() || 1) - 1,
        ($self->_getYear() || 1900) - 1900);
    
    return strftime($format, @date); 
}

sub cmpDate {
    my $self = shift;
    my $date = shift;

    if (!$self->isValidDate()) {
        # I'm invalid, but the other one isn't, it should be ahead of me.
        if ($date->isValidDate()) {
            return 1;
        }
        else {
            # Both are invalid, consider them equivelent.
            return 0;
        }
    }

    # I'm valid, but the other one isn't, i should be ahead of it.
    if (!$date->isValidDate()) {
        return -1;
    }

    my $diff = $self->getTimeApart($date);

    return 0 <=> $diff;
}

# Legacy method
sub isNow {
    my $self = shift;
    return $self->getIsNow();
}

sub _init {
    my $self = shift;
    my $input = shift;

    my ($year, $month, $day, $hour, $min, $sec, $ampm);

    if ($self->isValidHashRef($input)) {
        # Hashref input
        $year  = $input->{'year'};
        $month = $input->{'month'};
        $day   = $input->{'day'};
        $hour  = $input->{'hour'};
        $min   = $input->{'min'};
        $sec   = $input->{'sec'};
        $ampm  = $input->{'ampm'};
    } elsif ($input =~ /^0000-00-00 00:00:00$/) {
        # MySQL 'zero' date...leave values undef
    } elsif ($input =~ /^(\d\d\d\d)-(\d\d)-(\d\d) (\d\d):(\d\d):(\d\d)$/) {
        # MySQL date...leading zeros are removed
        ($year, $month, $day, $hour, $min, $sec) = ($1, $2+0, $3+0, $4+0, $5+0, $6+0);
    } elsif ($input =~ /^(\d\d\d\d)-(\d\d)-(\d\d)$/) {
        # MySQL date with no time
        ($year, $month, $day, $hour, $min, $sec) = ($1, $2+0, $3+0, 0, 0, 0);
    } elsif ($input =~ /^(\d{1,2})\D(\d{1,2})\D(\d\d\d\d) (\d{1,2}):(\d|[0-5][0-9])([^\d]|$)/){
        # Form input
        ($month, $day, $year, $hour, $min, $sec) = ($1, $2, $3, $4, $5, 0);
    } elsif ($input =~ /^(\d\d\d\d)(\d\d)(\d\d)(\d\d)(\d\d)(\d\d)$/) {
        # ISO 8601 date
        ($year, $month, $day, $hour, $min, $sec) = ($1, $2, $3, $4, $5, $6);
    }elsif ($input =~ /^\w+\s+(\w+)\s+(\d+)\s+(\d\d):(\d\d):(\d\d)\s*\w*\s+(\d\d\d\d)$/){
        #system date
        ($year, $month, $day, $hour, $min, $sec) = ($6, Decode_Month($1), $2, $3, $4, $5);

    } elsif ($input =~ /^\w+,\s+(\d+)\s+(\w+)\s+(\d{4})\s+(\d\d):(\d\d):(\d\d)\s+\w+$/) {
        ($year, $month, $day, $hour, $min, $sec) = ($3, Decode_Month($2), $1, $4, $5, $6);
    } elsif ($input =~ /^\d+$/) {
        # Unix date
        ($sec, $min, $hour, $day, $month, $year) = localtime($input);
        $year += 1900;
        $month++;
    } elsif ($input eq 'now') {
        # Moving 'now' date
        $self->setIsNow(TRUE);
        return SUCCESS;
    } else {
        return FAIL;
    }
    
    $self->setDate($year, $month, $day);
    $self->setTime($hour, $min, $sec, $ampm);
    $self->setIsNow(FALSE);
    return SUCCESS;
}
    
sub _addYMD {
    my $self = shift;
    my $y = shift || 0;
    my $m = shift || 0;
    my $d = shift || 0;
    
    return FAIL if $self->isEmpty();

    my ($year, $month, $day) = Add_Delta_YMD($self->_getYear(), $self->_getMonth(), $self->_getDay(), $y, $m, $d);
    
    return $self->setDate($year, $month, $day);
}

sub _addHMS {
    my $self = shift;
    my $h = shift || 0;
    my $m = shift || 0;
    my $s = shift || 0;

    return FAIL if $self->isEmpty();

    my ($year, $month, $day, $hour, $min, $sec) = Add_Delta_DHMS($self->_getYear(), $self->_getMonth(), $self->_getDay(), 
                                            $self->_getHour(), $self->_getMin(), $self->_getSec(),
                                            0,$h,$m,$s);
    return $self->setTime($hour, $min, $sec);
}

sub _updateToNow {
    my $self = shift;

    return SUCCESS unless $self->getIsNow();

    my ($sec, $min, $hour, $day, $month, $year) = localtime();

    $self->setDate($year + 1900, $month + 1, $day);
    $self->setTime($hour, $min, $sec);
    
    return SUCCESS;
}

sub _getAccessorDefinition {
    return [
        {
            name => 'IsNow',
            key  => '_is_now',
            type => 'Boolean',
        },
        {
            name => 'Sec',
            key  => '_sec',
            type => 'Integer',
            private_get => TRUE,
        },
        {
            name => 'Min',
            key  => '_min',
            type => 'Integer',
            private_get => TRUE,
        },
        {
            name => 'Hour',
            key  => '_hour',
            type => 'Integer',
            private_get => TRUE,
        },
        {
            name => 'Day',
            key  => '_day',
            type => 'Integer',
            private_get => TRUE,
        },
        {
            name => 'Month',
            key  => '_month',
            type => 'Integer',
            private_get => TRUE,
        },
        {
            name => 'Year',
            key  => '_year',
            type => 'Integer',
            private_get => TRUE,
        },
    ];
}


1;

__END__