package Ernad::Dates; use strict; use warnings; use Carp qw(cluck longmess shortmess croak confess); use Cwd 'abs_path'; use Data::Dumper; use Date::Calc qw(Add_Delta_Days); use Date::Format; use File::Basename; use Krichel::Shoti; use Ernad::Constant; my $seconds_in_a_day=24*60*60; my $format='%Y-%m-%d'; my $time_format="%Y\x{2012}%m\x{2012}%d %H:%M:%S"; sub mtime { my $file=shift // confess "I need a file here."; if(not -f $file) { confess "I can't see the file '$file'."; } my ($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size, $atime,$mtime,$ctime,$blksize,$blocks) = stat($file); return $mtime; } sub lmtime { my $file=shift // confess "I need a file here."; if(not -l $file) { confess "I can't see the link '$file'."; } my $target=abs_path($file) or confess "The link $file is broken"; my $mtime=&mtime($target); return $mtime; } sub mshoti { my $file=shift // confess "I need a file here."; my $time=&mtime($file); my $shoti=&Krichel::Shoti::make($time); return $shoti; } sub mdate { my $file=shift // confess "I need a file here."; my $time=&mtime($file); my $date=time2str($format,$time); return $date; } sub mtime_string { my $file=shift // confess "I need a file here."; my $time=&mtime($file); my $date=time2str($time_format,$time); return $date; } sub get_shift { my $date=shift // confess "I need a date here."; my $shift=shift // confess "I need a number here."; if(not $shift=~m|^-*\d+$|) { confess "Your shift argument needs to be an integer, $shift does not qualily."; } $date=~m|^(\d{4})-(\d{2})-(\d{2})$| or confess "I need a better date than '$date'"; my $year=$1; my $month=$2; my $day=$3; my @dated=&Add_Delta_Days($year,$month,$day,$shift); $year=$dated[0]; $month=$dated[1]; if(length($month)<2) { $month="0$month"; } $day=$dated[2]; if(length($day)<2) { $day="0$day"; } $date="$year-$month-$day"; return $date; } sub numeric { my $date=shift; $date=~m|^(\d{4})-(\d{2})-(\d{2})$| or confess "I need a better date than '$date'"; $date=~s|-||g; return $date; } ## $in has dates as keys sub ge_earliest_date_from_hash { my $in=shift; my @dates=sort (keys %{$in}); return $dates[0]; } sub pretty_date { my $date=shift or confess "I need a date here."; my $pretty_date=$date; $pretty_date=~s|-|\x{2012}|g; return $pretty_date; } sub date_to_dadi { my $date=shift or confess "I need a date here."; my $dadi=substr($date,0,4)."/$date"; return $dadi; } sub dadi_to_dati { my $dadi=shift or confess "I need a date here."; my $date=substr($dadi,5); return $date; } ## $in has dates as keys sub get_latest_date_from_hash { my $in=shift; my @dates=sort (keys %{$in}); return $dates[$#dates]; } ## $in has dates as keys sub calculate_date_weights { my $in=shift; my $earliest=&get_earliest_date_from_hash($in); my $latest=&get_latest_date_from_hash($in); my $span=diff_dates($earliest,$latest); my $diffs={}; my $total=0; foreach my $date (keys %{$in}) { if(not defined($in->{$date})) { next; } my $diff=&diff_dates($date,$earliest); $total+=$diff; $diffs->{$date}=$diff; } my $weights={}; foreach my $date (keys %{$in}) { $weights->{$date}=$diffs->{$date}/$total; } return $weights; } ## $in has dates as keys sub average_by_date { my $in=shift; my $weights=&calculate_date_weights($in); my $average=0; foreach my $date (keys %{$in}) { $average+=$weights->{$date} * $in->{$date}; } return $average; } sub pretty_today { my $time=shift // time; my $date=time2str("%Y\x{2012}%m\x{2012}%d", $time); return $date; } sub pretty_time { my $time=shift // time; my $date=time2str("%Y\x{2012}%m\x{2012}%d %H:%M:%S", $time); return $date; } sub get_past_dates_from_number { my $number=shift // ''; my $start_date=shift // ''; if(not $number=~m|^\d+$|) { confess "The first argument must be an integer."; } if($start_date) { if(not $start_date=~m|^\d{4}-\d{2}-\d{2}$|) { confess "The argument must be a date, not '$start_date'."; } } else { $start_date=&today(); } my $dates=[]; if(not $number=~m|^\d+|) { confess "I need a different number than '$number'."; } ## we never look at today's date if(not $number > 0) { return $dates; } my $start=0; if($start_date) { $start=&get_time_on_date($start_date); ## to start from the given day $start+=$seconds_in_a_day; } else { $start=time(); } my $count=0; while($number>0) { my $time=$start - $number * $seconds_in_a_day; $dates->[$count++]=time2str($format,$time); $number--; } return $dates; } ########################################################################## ## from Common sub today { my $date=time2str("%Y-%m-%d", time); return $date; } sub get_up_date { my $date=time2str("%Y\x{2012}%m\x{2012}%d", time); return $date; } sub get_update { my $date=time2str('%Y-%m-%d', time); return $date; } ## FixMe: change to compare sub compare_dates { my $early=shift // confess "I need an early date here."; my $late=shift // confess "I need a late date here."; $early=~m|^(\d{4})-(\d{2})-(\d{2})$| or confess "You gave me a bad date '$early'"; my $early_time="$1$2$3"; $late=~m|^(\d{4})-(\d{2})-(\d{2})$| or confess "You gave me bad date '$late'"; my $late_time="$1$2$3"; if($late_time > $early_time) { return 1; } if($late_time < $early_time) { return -1; } return 0; } ## FIXED FixMe: change to compare sub compare { my $early=shift // confess "I need an early date here."; my $late=shift // confess "I need a late date here."; $early=~m|^(\d{4})-(\d{2})-(\d{2})$| or confess "You gave me a bad date '$early'"; my $early_time="$1$2$3"; $late=~m|^(\d{4})-(\d{2})-(\d{2})$| or confess "You gave me bad date '$late'"; my $late_time="$1$2$3"; if($late_time > $early_time) { return 1; } if($late_time < $early_time) { return -1; } return 0; } ## later date come second sub diff_dates { my $d1=shift; my $d2=shift; ## construct containing the parsed dates my $d; my $count=0; foreach my $in ($d1,$d2) { $in=~m|^(\d{4})-(\d{2})-(\d{2})| or confess "bad date '$in'."; $d->[$count]->[0]=$1; $d->[$count]->[1]=$2; $d->[$count]->[2]=$3; $count++; } if(not &Date::Calc::check_date(@{$d->[0]})) { # confess "The date is not $d1 is not valid."; return undef; } if(not &Date::Calc::check_date(@{$d->[1]})) { # confess "The date is not $d1 is not valid."; return undef; } my $delta=Date::Calc::Delta_Days(@{$d->[0]},@{$d->[1]}); return $delta; } sub stretch_paper_date { my $in=shift // return ''; if($in=~m|^\d{4}$|) { return "$in"."-01-01"; } if($in=~m|^\d{4}-\d{2}$|) { return "$in"."-01"; } if($in=~m|^\d{4}-\d{2}-\d{2}$|) { return "$in"; } return ''; } sub is { my $in=shift // confess "I need the input defined."; if($in=~m/^[0-9]{4}-(((0[13578]|(10|12))-(0[1-9]|[1-2][0-9]|3[0-1]))|(02-(0[1-9]|[1-2][0-9]))|((0[469]|11)-(0[1-9]|[1-2][0-9]|30)))$/) { return 1; } return 0; } sub paper_age { my $in=shift // return ''; my $verbose=shift // ''; $in=&stretch_paper_date($in) // return ''; if($verbose) { print "The stretch date is $in\n"; } return diff_dates($in,&today()); } sub oldest_paper_age { my $text_ele=shift // confess "I need a text element here."; my $default=shift // confess "I need a default element here"; my $verbose=shift // ''; my $amf_ns=$Ernad::Constant::c->{'amf_ns'} // die "I need amf_ns defined here."; ## take the earliest dates my @date_eles=$text_ele->getElementsByTagNameNS($amf_ns,'date')->get_nodelist(); if(not scalar(@date_eles)) { if($verbose) { print "I have no date elements\n"; } return $default; } else { my $oldest_age=0; foreach my $date_ele (@date_eles) { my $date=$date_ele->textContent; if($verbose) { print "I found a date $date\n"; } my $age=&Ernad::Dates::paper_age($date,$verbose); ## if an invalid date was supplied, make it extremely old if(not defined($age)) { return 99999999999999999999; } if(not $age) { $age=0; } if($age>$oldest_age) { $oldest_age=$age; } } if(not $oldest_age) { return $default; } else { return $oldest_age; } } ## confess "I should not be reaching this line"; } ############################################################################# ## old stuff that needs clearing #compares two dates, returns 1 if they're equal and 0 otherwise sub DCEqual { my ( $d1, $d2 ) = @_; my $i; for( $i = 0; $i < scalar( @$d1 ); $i++ ) { if( @$d1[$i] != @$d2[$i] ) { return 0; } } return 1; } #compares two dates, returns 1 if first is greater and 0 otherwise sub DCGreater { my ( $d1, $d2 ) = @_; my $i; for( $i = 0; $i < scalar( @$d1 ); $i++ ) { if( $$d1[$i] < $$d2[$i] ) { return 0; } if( $$d1[$i] > $$d2[$i] ) { return 1; } } return 0; } #lower sub DCLower { my ( $d1, $d2 ) = @_; my $i; for( $i = 0; $i < scalar( @$d1 ); $i++ ) { if( @$d1[$i] < @$d2[$i] ) { return 1; } if( @$d1[$i] > @$d2[$i] ) { return 0; } } return 0; } sub DoZero { my $n = $_[0]; if( $n < 10 ) { return "0$n"; } return $n; } #returns string with current date/time sub CurrentAsString { # my ( $sec, $min, $hour, $mday, $mon, $year, $wday, $yday, $isdst ); my @data; $#data = 9; @data = localtime( time ); $data[4]++; $data[5] += 1900; my $sz = 6; $sz = $_[0] if( scalar( @_ ) >= 1 ); my $result = ""; for( my $i = 0; $i < $sz; $i++ ) { $result = $result.DoZero( $data[5 - $i] ); $result = $result."-" if( $i < $sz - 1 ); } return $result; } 1;