#!/usr/bin/perl -w use strict; my $VERSION="1.2.0"; =head INFORMATION ##################################################################### Author : Sanjoga Sahu Modification : 28th, Apr, 2009 (V1.0.0) [Initial Version] 20th, Oct, 2009 (V1.1.0) [Additional Functionality Addition] 29th, Apr, 2010 (V1.2.0) [Modified For Job dependancy] About : This is a simple and effective Autosys Job report Generator tool. How to set alias Help : ------------------------- Add an alias in .profile/.bashrc file alias ajr=/path/autosys_job_reporter_1.2.0.pl OR alias b=/path/autosys_job_reporter_1.2.0.pl Usage : ------------------------- autosys_job_reporter_1.2.0.pl : Provides Information of Job's Important Attributes along with the Status & more... Options : autosys_job_reporter_1.2.0.pl autosys_job_reporter_1.2.0.pl [<-adDhpqtu>] -h : Help. -a : All Options. -u : Upstream Dependency. -d : Downstream Dependency. -D : Upstream and Downstream Dependency (job_depends). -p : Previous Runs. -q : Jil of Job. -t : Calculates the Run Time of All Previous Runs. ##################################################################### Color Foreground Background black 30 40 red 31 41 green 32 42 yellow 33 43 blue 34 44 magenta 35 45 cyan 36 46 white 37 47 bash$ echo -e "\033[1m This is bold text. \033[0m" bash$ echo -e "\033[4m This is underlined text. \033[0m" =cut $|=10; my $id=`id`; chomp $id; my $wide_chk_lenth=30; my $no_sec=0; my $user; my $box_log; my $log_flg=0; my $add_info=1; my $log_name="autosys_job_reporter.errlog"; my %GLOBAL_VAR=(); if($id=~ /(\=\d+?)\s*\((.+?)\)/) { $user=$2; } if(defined $user) { if(-e "/home/$user" && -w "/home/$user") { unless(-d "/home/$user/log") { system("mkdir /home/$user/log"); } $box_log="/home/$user/log/$log_name"; $log_flg=1; } elsif(-e "/$user" && -w "/$user") { $box_log="/$user/$log_name"; $log_flg=1; } } #print "$box_log\n"; my $job=&trim($ARGV[0]); $job=&valid($job); #print "JOB:--$job--\n"; my $num_arg=scalar(@ARGV); #print "ARGV--$num_arg--\n"; my $opts; if($num_arg > 1) { shift(@ARGV); foreach my $op (@ARGV) { &valid_opts($op); } $opts=join("",@ARGV); $opts=~ s/\-//g; &check_opts($opts); #print "MORE...$opts...\n"; } unless(defined $opts) { $opts="n"; } #print "OPTS=$opts=\n"; &job_check($job,$opts); #____PROG_END____# ####################### SUBROUTINE : job_check() #################### =head 1. Check the job whether exist or not. 2. Gathers required box job and desired job's infromated output and prints. 3. Prints Additional Information of the job. =cut sub job_check { my ($job, $opts)=@_; my $rec; $job=&trim($job); my $box_f=0; $rec=`autorep -J $job -q -l0`; $rec=&trim($rec); my $rec_orig=$rec; $rec=~ s/\n/_##_/g; $rec=$rec."_##_"; #print "$rec\n"; if(defined $job && $job ne "") { my $box; if($rec=~/Invalid\s+Job\s+Name/i) { print "$rec_orig\n"; $job=&valid(""); } if($rec=~/insert_job\s*\:\s*(.+?)\s*job_type:\s*b\s*_\#\#\_/) { $box=$1; $box_f=1; #print "---IN 1\n"; } if($rec=~/box_name\s*\:\s*(.+?)\s*\_\#\#\_/) { $box=$1; #print "---IN 2\n"; } if(defined $box && $box ne "") { print "\n\033[1m================================================================\033[0m\n"; print "\033[44m\033[37m\033[1mBox Information : $box\033[0m\n"; my $jr=`autorep -J $box`; my $w=&jr_wide_check($jr); if($w==1) { $jr=`autorep -J $box -w`; } my @lines=split(/\n/,$jr); foreach my $li (@lines) { if($li=~ /\b$job\b/) { print "\033[45m\033[37m\033[1m$li\033[0m\n"; } else { print "$li\n"; } } print "\n"; if($box_f==1) { print "\033[44m\033[37m\033[1mBox Jil : $job\033[0m\n"; print "\n$rec_orig\n"; print "\n\033[1m================================================================\033[0m\n"; #print "\n================================================================\n"; exit(0) if($opts eq 'n'); } } else { print "\n\033[1m================================================================\033[0m\n"; print "\033[44m\033[37m\033[1mNo Box Job Found for this Job.\033[0m\n"; my $jr=`autorep -J $job`; my $w=&jr_wide_check($jr); if($w==1 ) { $jr=`autorep -J $job -w`; } #print "$jr"; my @lines=split(/\n/,$jr); foreach my $li (@lines) { if($li=~ /\b$job\b/) { print "\033[45m\033[37m\033[1m$li\033[0m\n"; } else { print "$li\n"; } } } ##################################################################### if($box_f !=1) { my ($prof, $script, $out, $err, $watch, $desc, $cond, $machine,$owner); my $prof_f=0; if($rec=~/profile\s*\:\s*(.+?)\s*\_\#\#\_/) { $prof=$1; $prof=&trim($prof); if(defined $prof && $prof ne "") { $prof_f=1; } } print "\n================================================================\n"; print "\033[44m\033[37m\033[1mJob Information : $job\033[0m\n"; ################### Serching Important Attributes ################### if($rec=~ /description\s*\:\s*(.+?)\s*\_\#\#\_/) { $desc=$1; print "Description: $desc\n"; } if($rec=~ /condition\s*\:\s*(.+?)\s*\_\#\#\_/) { $cond=$1; print "Condition: $cond\n"; } if($rec=~ /machine\s*\:\s*(.+?)\s*\_\#\#\_/) { $machine=$1; print "[machine: $machine] "; } if($rec=~ /owner\s*\:\s*(.+?)\s*\_\#\#\_/) { $owner=$1; print "[owner: $owner] "; } print "\n"; print "\n"; if($rec=~ /command\s*\:\s*(.+?)\s*\_\#\#\_/) { $script=$1; } if($rec=~ /std_out_file\s*\:\s*(.+?)\s*\_\#\#\_/) { $out=$1; } if($rec=~ /std_err_file\s*\:\s*(.+?)\s*\_\#\#\_/) { $err=$1; } if($rec=~ /watch_file\s*\:\s*(.+?)\s*\_\#\#\_/) { $watch=$1; } ########################## Printing Attributes ###################### &print_attr($script, $prof_f,$prof,"ls-no","command"); &print_attr($out, $prof_f,$prof,"ls-yes","std_out_file"); &print_attr($err,$prof_f,$prof,"ls-yes","std_err_file"); &print_attr($watch, $prof_f,$prof,"ls-yes","watch_file"); &print_attr($prof, $prof_f,$prof,"ls-no","profile"); print "\n\033[1m================================================================\033[0m\n"; } ###################### Additional Information ####################### my $flg_p=0; if($opts ne "n") { my @all_opts=split(/|/,$opts); my $all=join(" ",@all_opts); if($all=~ /a/) { &jr_q($job) if($box_f !=1); &jr_u($job); &jr_d($job); &jr_p($job,1); &jr_t($job); $flg_p=1; } else { foreach my $op (@all_opts) { if($op eq "q" && $box_f !=1) { &jr_q($job); $flg_p=1; } if($op eq "u") { &jr_u($job); $flg_p=1; } if($op eq "D") { &jr_D($job); $flg_p=1; } if($op eq "d") { &jr_d($job); $flg_p=1; } if($op eq "p") { &jr_p($job,1); $flg_p=1; } if($op eq "t") { &jr_t($job); $flg_p=1; } if($op eq "h") { print "\033[44m\033[37m\033[1mInformation About $0 : [-h]\033[0m\n"; &usage(); $flg_p=1; } } } print "\n\033[1m================================================================\033[0m\n" if($flg_p==1); } }#job defined } ###################### SUBROUTINE : trim ()########################## #removes prefix and postfixed space/newline/tab from input string sub trim { my ($str)=@_; return undef unless(defined $str); $str=~s/^\s+|\s+$//g; return $str; } ###################### SUBROUTINE : valid ########################### #Checks the string not to be a NULL one. sub valid { my ($job)=@_; if(!defined $job) { &usage(); exit(11); } elsif($job eq "") { &usage(); exit(13); } elsif($job eq "-h") { print "\033[44m\033[37m\033[1mInformation About $0 : [-h]\033[0m\n"; &usage; exit(0); } else { return $job; } } ##################################################################### sub usage { print "\nUsage:\n\n$0 : Provides Information of Job's Important Attributes along with the Status & more...\n"; print "\nOptions :\n"; print "$0 \n"; print "$0 [<-adDhpqtu>]\n\n"; print "-h : Help.\n-a : All Options.\n-u : Upstream Dependency.\n-d : Downstream Dependency.\n-D : Upstream and Downstream Dependency (job_depends).\n-p : Previous Runs.\n-q : Jil of Job.\n-t : Calculates the Run Time of All Previous Runs.\n\n"; } ####################### SUBROUTINE : valid_opts() ################### #checks the prefix of options. sub valid_opts { my ($str)=@_; unless($str=~ /^-/ && $str ne "-") { print "Invalid Option :$str\n"; &usage(); exit(1); } } ####################### SUBROUTINE : check_opts() ################### #validates the options provided sub check_opts { my ($str)=@_; my @all_opts=split(/|/,$str); #print "ALL_OPTS===@all_opts===\n"; foreach my $op (@all_opts) { unless($op=~ /a|h|p|q|t|u|d|D/) { print "Invalid Option :$op\n"; &usage(); exit(1); } } } ##################### SUBROUTINE : substitute_WIN() ################# #subtitutes Win NT charaters with Unix charaters. #This a tailor made subroutine can be changed as per the requirment. sub substitute_WIN { my ($str)=@_; $str=&ini($str); # ADD YOUR CODE HERE FOR HANDLING THE WIN<>UNIX PATH/ALIAS $str=~ s|\\|/|ig; return $str; } ###################### SUBROUTINE : ini ()########################### #initialize input string sub ini { my ($str)=@_; return "" unless(defined $str); return $str; } ################### SUBROUTINE : remove_env_str ##################### #removes unwanted lines/character from output after running the profile sub remove_env_str { my ($str)=@_; $str=&ini($str); my ($str_un,$str_nc)=split(/\//,$str,2); $str_nc=&ini($str_nc); if($str=~/\//) { $str_nc='/'.$str_nc; } $str_nc=&trim($str_nc); if($str_nc eq "") { $str_nc=$str; } return $str_nc; } ##################### SUBROUTINE : ls_file() ######################## # It lists the file. retuns not found message if the file can't be listed. sub ls_file { my ($file)=@_; my $ls_file; if(-f $file) { $ls_file=`ls -lrt \"$file\"`; chomp $ls_file; return $ls_file } else { return "$file [File Not Found]"; } } ################# SUBROUTINE : print_attr() ######################### # Prints the result in a desired format. sub print_attr { my ($attr, $flag, $prof,$ls_flg, $type)=@_; $attr=&trim($attr); #print "=====$attr, ===$flag, ==$prof,=$ls_flg, -$type\n"; if($flag==1) { if(defined $attr && $attr ne "") { $attr=~ s/\bcp\b/CP/g; $attr=~ s/\bmv\b/MV/g; $attr=~ s/\brm\b/RM/g; $attr=~ s/\>/\\>/g; $attr=~ s/\ $box_log \necho $attr`; #print "++++++++\n"; } else { $val_scr=`__profile=$prof \n AUTO_JOB_NAME=$job \n . $prof \necho $attr`; } my $att_flg=0; if(defined $val_scr && $val_scr ne "") { $val_scr=&substitute_WIN($val_scr); $val_scr=&remove_env_str($val_scr); } else { $val_scr=$attr; $ls_flg='ls-no'; } $val_scr=~ s/\bCP\b/cp/g; $val_scr=~ s/\bMV\b/mv/g; $val_scr=~ s/\bRM\b/rm/g; $val_scr=~ s/\bAND\b/and/g; $val_scr=~ s/\bOR\b/or/g; $val_scr=~ s/\d{6}.out/*.out/g; $val_scr=~ s/\d{6}.err/*.err/g; if($ls_flg eq "ls-yes") { $val_scr=&ls_file($val_scr); } print "$type\: $val_scr\n"; } } else { if(defined $attr && $attr ne "") { my $val_scr=&substitute_WIN($attr); if($ls_flg eq "ls-yes") { $val_scr=&ls_file($val_scr); } print "$type\: $val_scr\n"; } } return; } ############### SUBROUTINE : jr_wide_check() ######################## =head Checks if there is a requirment of printing (wide spaced job report). sends a flag 1 if the job status string contains dots else 0 =cut sub jr_wide_check { my ($str)=@_; $str=~ s/\n/_#_#_/g; if($str=~ /\.\.\./) { return(1); } elsif(length $str >= $wide_chk_lenth) { return(1); } else { return(0); } } ######################### SUBROUTINE : jr_q() ####################### #shouws jil information of the job sub jr_q { my ($job)=@_; print "\n"; print "Please Wait..."; my $q=`autorep -J $job -q -l0`; $q=&trim($q); print "\r\033[44m\033[37m\033[1mAdditional Information #$add_info : [-q] Jil of ($job)\033[0m\n\n"; $add_info++; print "$q\n"; #print "\n\033[1m================================================================\033[0m\n"; return; } ######################### SUBROUTINE : jr_u() ####################### #shows upstream dependency sub jr_u { my ($job)=@_; print "\n"; print "Please Wait..."; my $res=`which job_depends`; if($res !~ /^no\s+/) { my $depend=`job_depends -c -J $job`; my $res; my @dep=split(/\n/,$depend); my %depend; my %value; my $depnd_flg=0; foreach my $dd (@dep) { $dd=&trim($dd); next if($dd eq ""); if($dd=~ /Atomic\s+Condition/i) { $depnd_flg=1; } if($dd=~ /Dependent\s+Job\s+Name/i) { $depnd_flg=0; } if($depnd_flg) { if($dd=~/^SUCCESS\(|^NOTRUNNING\(|^DONE\(|^s\(|^n\(|^d\(/i) { my @val=split(/\s+/i, $dd); my $job=$val[0]; my $index=$#val; my $cond=$val[$index]; $job=~ s/^SUCCESS\(|^NOTRUNNING\(|^DONE\(|^s\(|^n\(|^d\(//gi; $job=&trim($job); $job=~ s/^\(|\)$//g; $depend{$job}=$cond; } elsif($dd=~/^VALUE\(|^v\(/) { my @val=split(/\s+/i, $dd); my $job=$val[0]; my $index=$#val; my $cond=$val[$index]; $job=~ s/^VALUE\(|^v\(//g; $job=&trim($job); $job=~ s/^\(|\)$//g; $value{$job}=$cond; } } } my $num=scalar(keys %depend); my $glb=scalar(keys %value); if($num == 0 && $glb ==0) { $res="No Upstream Dependency Found!\n"; } else { foreach my $d (keys %depend) { my $jr=`autorep -J $d|grep "$d"`; $jr=&trim($jr); my $cond; $cond="\033[30m\033[42m[ Dependecy Status: $depend{$d} ]\033[0m" if($depend{$d}=~ /T/i); $cond="\033[30m\033[41m[ Dependecy Status: $depend{$d} ]\033[0m" if($depend{$d}=~ /F/i); $res .=$jr." $cond\n"; } $res .="\nGlobal Name Value Last Changed\n------------------------- ------------------------- --------------------\n" if(scalar keys %value >0); foreach my $d (keys %value) { my $jr=`autorep -G $d|grep "$d"`; $jr=&trim($jr); my $cond; $cond="\033[30m\033[42m[ Dependecy Status: $value{$d} ]\033[0m" if($value{$d}=~ /T/i); $cond="\033[30m\033[41m[ Dependecy Status: $value{$d} ]\033[0m" if($value{$d}=~ /F/i); $res .=$jr." $cond\n"; } } print "\r\033[44m\033[37m\033[1mAdditional Information #$add_info : [-u] Upstream Dependency of ($job)\033[0m\n\n"; $add_info++; print "$res"; #print "\n\033[1m================================================================\033[0m\n"; } else { print "\r\033[44m\033[37m\033[1mAdditional Information #$add_info : [-u] Upstream Dependency of ($job)\033[0m\n\n"; $add_info++; print "\r\033[41m\033[1mAutosys Command : \'job_depends\' Not Found!\033[0m\n"; } #print "\n\033[1m================================================================\033[0m\n"; return; } ######################### SUBROUTINE : jr_D() ####################### #Shows Downstream Dependency sub jr_D { my ($job)=@_; print "\n"; print "Please Wait..."; my $res=`which job_depends`; if($res !~ /^no\s+/) { my $depend=`job_depends -c -J $job`; $depend=&trim($depend); print "\r\033[44m\033[37m\033[1mAdditional Information #$add_info : [-D] Job Dependencies of ($job)\033[0m\n"; print "$depend\n"; } return; } ######################### SUBROUTINE : jr_d() ####################### #Shows Downstream Dependency sub jr_d { my ($job)=@_; print "\n"; print "Please Wait..."; my $res=`which job_depends`; if($res !~ /^no\s+/) { my $depend=`job_depends -c -J $job`; my $res; my @dep=split(/\n/,$depend); my @depend; my $depnd_flg=0; foreach my $dd (@dep) { $dd=&trim($dd); #print "--$dd--\n"; if($dd=~ /Dependent\s+Job\s+Name/i) { $depnd_flg=1; } if($depnd_flg) { if($dd=~/SUCCESS\(|NOTRUNNING\(|DONE\(|s\(|n\(|d\(|v\(|VALUE\(/i) { my ($val, $odd)=split(/SUCCESS\(|NOTRUNNING\(|DONE\(|s\(|n\(|d\(|v\(|VALUE\(/i, $dd, 2); $val=&trim($val); $val=~ s/^\(|\)$//g; push(@depend,$val); } } } my $num=scalar(@depend); if($num == 0) { $res="No Downstream Dependency Found!\n"; } else { foreach my $d (@depend) { my $jr=`autorep -J $d|grep "$d"`; chomp $jr; $res .=$jr."\n"; } } print "\r\033[44m\033[37m\033[1mAdditional Information #$add_info : [-d] Downstream Dependency of ($job)\033[0m\n\n"; $add_info++; print "$res"; } else { print "\r\033[44m\033[37m\033[1mAdditional Information #$add_info : [-d] Downstream Dependency of ($job)\033[0m\n\n"; $add_info++; print "\r\033[41m\033[1mAutosys Command : \'job_depends\' Not Found!\033[0m\n"; } #print "\n\033[1m================================================================\033[0m\n"; return; } ######################### SUBROUTINE : jr_p() ####################### #shows previous job runs details sub jr_p { my ($job, $flg)=@_; print "\n" if($flg); print "Please Wait..." if($flg); my $res; #autorep -j $job -l0 -r -2|grep $job my $p=""; my $run=0; while( $p !~/Does\s+not\s+have\s+a\s+run/i) { $p=`autorep -j $job -l0 -r -$run|grep $job`; if($run==0 && $p !~/Does\s+not\s+have\s+a\s+run/i) { $res="Latest Run $run : $p"; $run++; } else { $res .="Previous Run $run : $p"; $run++; } } print "\r\033[44m\033[37m\033[1mAdditional Information #$add_info : [-p] Previous Runs of ($job)\033[0m\n\n" if($flg); $add_info++ if($flg); print "$res" if($flg); #print "\n\033[1m================================================================\033[0m\n"; return $res; } ######################### SUBROUTINE : jr_t() ####################### #shows time taken for job to complete. sub jr_t { my ($job)=@_; print "\n"; print "Please Wait..."; my $res=""; my $t=&jr_p($job,0); my @all=split(/\n/,$t); pop @all; foreach my $li (@all) { if($li =~ /\-\-/) { my ($prefix, $time_stamp)=split(/\:/,$li,2); my ($start, $end, $status); #yyyyyyyy ----- 02/24/2007 23:38:41 SU 0/0 #xxxxxxxx ----- 08/01/2008 14:21 OI 57904994/1 if($time_stamp =~ m|\s+\-\-\-\-\-\s+(\d{2}/\d{2}/\d{4}\s+\d{2}:\d{2}(:\d{2})?)\s+(\w{2})\s+|) { $end=&trim($1); $status=$3; my $sec=$2; $end=~ s|(\d{2})/(\d{2})/(\d{4})|$3-$1-$2|g; if(defined $sec) { $start="####-##-## ##:##:##"; } else { $start="####-##-## ##:##"; $no_sec=1; } $res .="$prefix: $start to $end $status ==> N/A for Time Calc.\n"; } #zzzzzzxxxxxxx 03/04/2009 20:15:11 ----- RU 4411130/1 #ttttttttttttt 06/24/2009 22:50 ----- RU 68570413/1 elsif($time_stamp =~ m|\s+(\d{2}/\d{2}/\d{4}\s+\d{2}:\d{2}(:\d{2})?)\s+\-\-\-\-\-\s+(\w{2})\s+|) { $start=&trim($1); $status=$3; my $sec=$2; $start=~ s|(\d{2})/(\d{2})/(\d{4})|$3-$1-$2|g; if(defined $sec) { $end="####-##-## ##:##:##"; } else { $end="####-##-## ##:##"; $no_sec=1; } $res .="$prefix: $start to $end $status ==> "; $end=`date "+%m/%d/%Y %H:%M:%S"`; chomp $end; $start=~ s|(\d{2})/(\d{2})/(\d{4})|$3-$1-$2|g; $end=~ s|(\d{2})/(\d{2})/(\d{4})|$3-$1-$2|g; my ($days,$hr,$min, $secs)=&time_taken(date1 => $start,date2 => $end); $res .="$days Days, $hr Hr, $min Min, $secs Sec. (Time Elapsed Till Now)\n"; } elsif($time_stamp =~ m|\s+\-\-\-\-\-\s+\-\-\-\-\-\s+(\w{2})\s+|) { $status=$1; if($no_sec) { #not satisfing now... $res .="$prefix: ####-##-## ##:## to ####-##-## ##:## $status ==> N/A for Time Calc.\n"; } else { #$res .="$prefix: ####-##-## ##:##:## to ####-##-## ##:##:## $status ==> N/A for Time Calc.\n"; $res .="$prefix: ####-##-## ##:## to ####-##-## ##:## $status ==> N/A for Time Calc.\n"; } } } else { #print "----$li---\n"; #$li : Latest Run 0 : 03/04/2009 05:21:38 03/04/2009 05:21:40 SU 4403364/1 my ($prefix, $time_stamp)=split(/\:/,$li,2); #print "--$time_stamp---\n"; #xxxxxxxxx 03/04/2009 05:21:38 03/04/2009 05:21:40 SU 4403364/1 #ddddddddd 06/24/2009 20:30 06/24/2009 20:32 SU 68570413/1 if($time_stamp=~ m|\s+(\d{2}/\d{2}/\d{4}\s+\d{2}:\d{2}(:\d{2})?)\s+(\d{2}/\d{2}/\d{4}\s+\d{2}:\d{2}(:\d{2})?)\s+(\w{2})\s+|) { my $start=&trim($1); my $end=&trim($3); my $status=$5; $no_sec=1 unless(defined $2); $start=~ s|(\d{2})/(\d{2})/(\d{4})|$3-$1-$2|g; $end=~ s|(\d{2})/(\d{2})/(\d{4})|$3-$1-$2|g; my ($days,$hr,$min, $sec)=&time_taken(date1 => $start,date2 => $end); $res .="$prefix: $start to $end $status ==> $days Days, $hr Hr, $min Min, $sec Sec.\n"; } } } print "\r\033[44m\033[37m\033[1mAdditional Information #$add_info : [-t] Run Time for ($job)\033[0m\n\n"; $add_info++; print "$res"; print "\nCurrent Time : " ,`date`; return; } ##################### SUBROUTINE : time_taken() ##################### =head Calculates the job run time. input string : key1 : Start date => value1 : YYYY-MM-DD hh:mm:ss key2 : End date => value2 : YYYY-MM-DD hh:mm:ss returns : days, hours, min, and sec. =cut sub time_taken (%) { my %args = @_; my @offset_days = qw(0 31 59 90 120 151 181 212 243 273 304 334); my $year1 = substr($args{'date1'}, 0, 4); my $month1 = substr($args{'date1'}, 5, 2); my $day1 = substr($args{'date1'}, 8, 2); my $hh1 = substr($args{'date1'},11, 2) || 0; my $mm1 = substr($args{'date1'},14, 2) || 0; my $ss1 = substr($args{'date1'},17, 2) if (length($args{'date1'}) > 16); $ss1 = 0 unless (defined $ss1); #print "$args{'date1'}\n"; #print "---$year1--$month1--$hh1--$mm1--$ss1--\n"; my $year2 = substr($args{'date2'}, 0, 4); my $month2 = substr($args{'date2'}, 5, 2); my $day2 = substr($args{'date2'}, 8, 2); my $hh2 = substr($args{'date2'},11, 2) || 0; my $mm2 = substr($args{'date2'},14, 2) || 0; my $ss2 = substr($args{'date2'},17, 2) if (length($args{'date2'}) > 16); $ss2 = 0 unless (defined $ss2); my $total_days1 = $offset_days[$month1 - 1] + $day1 + 365 * $year1; my $total_days2 = $offset_days[$month2 - 1] + $day2 + 365 * $year2; my $days_diff = $total_days2 - $total_days1; my $seconds1 = $total_days1 * 86400 + $hh1 * 3600 + $mm1 * 60 + $ss1; my $seconds2 = $total_days2 * 86400 + $hh2 * 3600 + $mm2 * 60 + $ss2; my $ssDiff = $seconds2 - $seconds1; my $dd = int($ssDiff / 86400); my $hh = int($ssDiff / 3600) - $dd * 24; my $mm = int($ssDiff / 60) - $dd * 1440 - $hh * 60; my $ss = int($ssDiff / 1) - $dd * 86400 - $hh * 3600 - $mm * 60; return ($dd, $hh, $mm , $ss); }