package RWDE::Time; use strict; use warnings; use RWDE::DB::Record; use RWDE::DB::DefaultDB; use base qw(RWDE::DB::DefaultDB RWDE::DB::Record); use vars qw($VERSION); $VERSION = sprintf "%d", q$Revision: 516 $ =~ /(\d+)/; =pod =head1 RWDE::Time Class for performing time related queries. RWDE doesn't use any external perl libraries, instead it queries the database set up in the project configuration file. =cut =head2 fetch_time({ timestamp, interval }) Fetch a calculated date. Provided a timestamp and the desired interval the database will be queried and the resulting calculation returned back. An added bonus is that the standard sql for dates can be used here when passing your parameters. For example, to return the timestamp representing 5 days for right now: RWDE::Time->fetch_time({ timestamp => 'now()', interval => "5 days"}); =cut sub fetch_time { my ($self, $params) = @_; my @required = qw( timestamp interval ); RWDE::RObject->check_params({ required => \@required, supplied => $params }); #insert regex for timestamp validation and interval validation... my $select = 'CAST(? as timestamp) + CAST(? as interval)'; my @query_params = ($$params{timestamp}, $$params{interval}); return $self->fetch_single({ select => $select, query_params => \@query_params }); } =head2 fetch_difference({ start_stamp, stop_stamp }) Fetch the number of days elapsed between two dates. Provided a start and stop date return the number of full days that have passed between the two. An added bonus is that the standard sql for dates can be used here when passing your parameters. Note the parameters can be formatted as timestamps but the method will cast them to dates anyway. If you are looking for the total elapsed time between two timestamps use fetch_exact_difference. For example, to return how many days have passed since New Years 2008: RWDE::Time->fetch_diff({ start_stamp => '01/01/2008 00:00:00', stop_stamp => 'now()' }); =cut sub fetch_diff { my ($self, $params) = @_; if (not defined $$params{start_stamp} or not defined $$params{stop_stamp}) { return; } my $select = 'CAST(? as date) - CAST(? as date)'; my @query_params = ($$params{stop_stamp}, $$params{start_stamp}); return $self->fetch_single({ select => $select, query_params => \@query_params }); } =head2 is_before({ start_stamp, stop_stamp }) Returns true if start_stamp is before stop_stamp, false otherwise =cut sub is_before{ my ($self, $params) = @_; RWDE::RObject->check_params({ required => ['start_stamp','stop_stamp'], supplied => $params }); #insert regex for timestamp validation and interval validation... my $select = "to_char(CAST(? as timestamp) - CAST(? as timestamp),'SS')"; my @query_params = ($$params{stop_stamp}, $$params{start_stamp}); my $diff = $self->fetch_single({ select => $select, query_params => \@query_params }); if ($diff > 0) { return 1; } else{ return 0; } } =head2 now() Fetch the timestamp that currently represents exactly "now". This is useful for timestamping events within the system, etc. RWDE::Time->now() would returns a timestamp that conforms to your database default timestamp representation =cut sub now { my ($self, $params) = @_; return $self->fetch_time({ timestamp => 'NOW()', interval => 0 }); } =head2 days_passed This is a macro to fetch_diff whereby the ending timestamp is always represented by the current date. This simply returns back the number of days that have passed between the start stamp and the time when the method is executed. =cut sub days_passed { my ($self, $params) = @_; my $interval = RWDE::Time->fetch_diff({ start_stamp => $$params{timestamp}, stop_stamp => 'now()' }); # extract the number from the db response with the optional minus #$interval =~ m/([-]?\d+)\s+(day)/; #my $days = $1; #unless (defined($days)) { # $days = 0; #} return $interval; } =head2 format_date Generate a time hash that represents the timestamp parameter. The method parses through the timestamp and separates each of the timestamp components into a separate key. date, time, year, month, and day are all represented within the time hash =cut sub format_date { my ($self, $params) = @_; my @required = qw( timestamp ); RWDE::RObject->check_params({ required => \@required, supplied => $params }); my @parts = split / /, $$params{timestamp}; my $time = {}; $$time{date} = $parts[0]; $$time{time} = $parts[1]; @parts = split(/-/, $$time{date}); $$time{year} = $parts[0]; $$time{month} = $parts[1]; $$time{day} = $parts[2]; return $time; } =head2 format_qdate Generate a qdate from the passed in timestamp parameter. =cut sub format_qdate { my ($self, $params) = @_; my @required = qw( timestamp ); RWDE::RObject->check_params({ required => \@required, supplied => $params }); my $time = $self->format_date({ timestamp => $$params{timestamp} }); return ("$$time{month}/$$time{day}/$$time{year}"); } =head2 format_rfc Generate an RFC 822 formatted date from the passed in timestamp parameter. RSS requires this specific RFC date formatting =cut sub format_rfc { my ($self, $params) = @_; my @required = qw( timestamp ); RWDE::RObject->check_params({ required => \@required, supplied => $params }); my $select = 'to_char(?::TIMESTAMP WITH TIME ZONE, ?)'; my @query_params = ($$params{timestamp}, 'Dy, DD Mon YYYY HH12:MI:SS TZ'); return $self->fetch_single({ select => $select, query_params => \@query_params }); } =head2 format_human Generate an arbitrary human readable date from the passed in timestamp parameter. The returned date formating is: YYYY-MM-DD HH12:MI:SS TZ =cut sub format_human { my ($self, $params) = @_; my @required = qw( timestamp ); RWDE::RObject->check_params({ required => \@required, supplied => $params }); my $select = 'to_char(?::TIMESTAMP WITH TIME ZONE, ?)'; my @query_params = ($$params{timestamp}, 'YYYY-MM-DD HH12:MI:SS TZ'); return $self->fetch_single({ select => $select, query_params => \@query_params }); } =head2 extract_dow Determine the day of week of a given timestamp parameter =cut sub extract_dow { my ($self, $params) = @_; my @required = qw( timestamp ); RWDE::RObject->check_params({ required => \@required, supplied => $params }); my $select = 'EXTRACT(DOW FROM ?::timestamp)'; my @query_params = ($$params{timestamp}); return $self->fetch_single({ select => $select, query_params => \@query_params }); } =head2 db_format_timestamp Take a database timestamp and make it look nice for humans to read. This is for Postgres database which tack on a numeric timezone. =cut sub db_format_timestamp { my ($self, $db_timestamp) = @_; return substr $db_timestamp, 0, 19; } 1;