#!/usr/bin/perl #this software copyright 2004, provided as-is. The author takes no liabilty or responsibility for use or misuse, functioning or misfunctioning of this software. use Getopt::Long; my $name = ""; my $version="0.2"; my $tclockdir=$ENV{HOME} . "/.tclock/default/"; my $sheet = "default"; my $progname="tclock"; my $long_progname="Command Line Time Clock"; my $verbose=1; my $rightNow=time; my $tty=0; #no tty formatting at this time #for date parsing my $sec; my $min; my $hour; my $mday, my $mon; my $year; my $wday; my $yday, my $isdst; #get time zone my @goo = gmtime(time()); my @foo = localtime(time()); my $tz = @goo[2] - @foo[2]; #useful for later my @monthnames=("", "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"); #better make sure that our dir exists if(-e $ENV{HOME} . "/.tclock/"){ } else{ mkdir $ENV{HOME} ."/.tclock/"; } #and that we have a default timesheet ready if(-e $ENV{HOME} . "/.tclock/default/"){ } else{ mkdir $ENV{HOME} ."/.tclock/default/"; } #also probably want to get the name, if there is one if(-e "$ENV{HOME}/.tclock/conf"){ open(NAME, "$ENV{HOME}/.tclock/conf") || die "Conf file exists, but\nit is unreadable. You\nhad best start to pray.\n"; $name = ; close(NAME); $name =~ s/\n//; } sub printHelp { print "Usage: $progname [options...]\n"; print "General Options:\n"; print "--help\t\t\t\t\tThis help information\n"; print "--version\t\t\t\tShow version information\n"; print "--name [yourname]\t\t\tSet your name\n"; print "-i | --in\t\t\t\tCheck in\n"; print "-o | --out\t\t\t\tCheck out\n"; print "-s | --status\t\t\t\tShow status\n"; print "-d | --daily [n]\t\t\tDisplay daily hours from n days back\n"; print "-w | --weekly [n]\t\t\tDisplay weekly hours from n weeks back\n"; print "-n | --new [timesheet name]\t\tCreate new timesheet\n"; print "-t | --timesheet [sheet] options...\tUse named timesheet instead of default\n"; print "\nNB: To set your name or create/use a timesheet with whitespace in the name, use quotation marks around the name.\n"; } sub parseEpochTime { my @moo = localtime(shift); for(my $i = 0; $i < 5; $i++){ if($moo[$i] < 10){ $moo[$i] = '0' . $moo[$i]; } } ($sec, $min, $hour, $mday, $mon, $year, $wday, $yday, $isdst)=@moo; $year+=1900; $mon++; } sub printVersion { print "$long_progname v$version\n"; } sub setName { $name = shift; `echo $name > $ENV{HOME}/.tclock/conf`; print "Your name has been changed to $name.\n"; } sub checkIn { if(-e "$tclockdir/markin"){ @array = stat("$tclockdir/markin"); $ctime = $array[10]; parseEpochTime($ctime); die "You are already checked in, as of $hour:$min:$sec, $monthnames[$mon] $mday, $year.\n"; } else { `touch $tclockdir/markin`; print "You are now checked in.\n"; } } sub checkOut { open(MARK, "$tclockdir/markin")||die "You are not checked in.\nHowever much you may wish,\nit will not be so.\n"; @array = stat(MARK); $ctime = $array[10]; unlink("$tclockdir/markin") || die "Could not unlink file!\nForsooth, I see this is bad.\nPerhaps you should cry.\n"; open(SHEET, ">>$tclockdir/timesheet") || die "Can't open timesheet!\nPermissions may sit badly\nlike grass blown by wind.\n"; $rightnow = time(); print SHEET "$ctime#$rightnow\n"; $temp = $rightnow - $ctime; $temp = $temp/3600; $temp = sprintf("%.2f", $temp) ; print "You are now checked out, having worked $temp hours.\n"; close(SHEET); } sub status { open(MARK, "$tclockdir/markin")||die "You are not checked in.\nI regret if you did hope,\nbut this cannot be.\n"; @array = stat(MARK); $ctime = $array[10]; parseEpochTime($ctime); my $diff = time() - $ctime; $diff = $diff/3600; $diff = sprintf("%.2f", $diff) ; print "You have been checked in for $diff hours, since $hour:$min:$sec, $monthnames[$mon] $mday, $year\n"; } sub newSheet { my $sheet = shift; $tclockdir = $ENV{HOME} . "/.tclock/"; if(-d "$tclockdir/$sheet"){ die "Uniqueness is scarce.\nA timesheet by that name does\nalready exist.\n"; } mkdir "$tclockdir/$sheet"; } sub daily { open(SHEET, "$tclockdir/timesheet") || die "The sheet as you type\ncannot be found. Or perhaps\nyour system is bunk.\n"; parseEpochTime(time()); my $day = shift; my $base = 86400*int(time()/86400); #get the start of our current day $base = $base + $tz*3600; $base = $base - $day*86400; #get as far back as we want to look my @info; my @times; #the entries we find within range foreach $line (){ @info = split('#', $line); #print"base: $base " . ($base + 86400) . " start: @info[0] end: @info[1]\n"; if((@info[0] >= $base)&&(@info[1] < $base+86400)){ #range is neatly within bounds push(@times, $line); } elsif((@info[0] < $base) && (@info[1] > $base)){ #range starts below range ends within (or past) if(@info[1] > $base+86400){ #start < base end > endofrange push(@times, $base . '#' . $base+86400); } else{ push(@times, $base . '#' . @info[1]); } } elsif((@info[0] < $base+86400)&&(@info[1] > $base)){ #start > base and < endofbase, end >= endofbase push(@times, @info[0] . '#' . $base+86400); } } ###at this point we have an array of the matching lines (or parts of lines) #now we print the results--this could be done in the above loop, but one more loop is a small price to pay for readability and possibly better customized output parseEpochTime($base); print "Daily timesheet starting $mon/$mday/$year:\n"; print "================================================================\n"; print "| Start Time | End Time | Hours |\n"; print "|====================|====================|====================|\n"; my $totalhours = 0; my $temp; my $diff; my $string; foreach $line (@times){ @info = split('#', $line); $temp = @info[1] - @info[0]; parseEpochTime($temp); $diff = $temp/3600; $diff = sprintf("%.2f", $diff) ; parseEpochTime(@info[0]); $string = "|" .$mon ."/" . $mday ."/" . $year ." $hour:$min:$sec "; while(length($string) <= 20){ $string = $string . " "; } print $string; parseEpochTime(@info[1]); $string = "|$mon" ."/" . $mday ."/" . $year ." $hour:$min:$sec "; while(length($string) <= 20){ $string = $string . " "; } print $string; $string = "|$diff"; while(length($string) <= 20){ $string = $string . ' '; } print $string . "|\n"; print "|--------------------------------------------------------------|\n"; $totalhours += $diff; } $string = "| Total Hours: $totalhours"; while(length($string) < 63){ $string = $string . ' '; } print "$string|\n"; $string = "| $name _________________"; while(length($string)<63){ $string = $string . ' '; } print "$string|\n"; print "|==============================================================|\n"; } sub weekly { open(SHEET, "$tclockdir/timesheet") || die "That sheet won't open.\nTypos are plenty. Perhaps\nyou just need a drink.\n"; parseEpochTime(time()); my $week = shift; my $base = 604800*int(time()/604800); #get the start of our current day $base = $base - 259200 + $tz*3600; $base = $base - $week*604800; #get as far back as we want to look my @info; my @times; #the entries we find within range foreach $line (){ @info = split('#', $line); #print"base: $base " . ($base + 604800) . " start: @info[0] end: @info[1]\n"; if((@info[0] >= $base)&&(@info[1] < $base+604800)){ #range is neatly within bounds push(@times, $line); } elsif((@info[0] < $base) && (@info[1] > $base)){ #range starts below range ends within (or past) if(@info[1] > $base+604800){ #start < base end > endofrange push(@times, $base . '#' . $base+604800); } else{ push(@times, $base . '#' . @info[1]); } } elsif((@info[0] < $base+604800)&&(@info[1] > $base)){ #start > base and < endofbase, end >= endofbase push(@times, @info[0] . '#' . $base+604800); } } ###at this point we have an array of the matching lines (or parts of lines) #now we print the results--this could be done in the above loop, but one more loop is a small price to pay for readability and possibly better customized output parseEpochTime($base); print "Daily timesheet starting $mon/$mday/$year:\n"; print "================================================================\n"; print "| Start Time | End Time | Hours |\n"; print "|====================|====================|====================|\n"; my $totalhours = 0; my $temp; my $diff; my $string; foreach $line (@times){ @info = split('#', $line); $temp = @info[1] - @info[0]; parseEpochTime($temp); $diff = $temp/3600; $diff = sprintf("%.2f", $diff) ; parseEpochTime(@info[0]); $string = "|" .$mon ."/" . $mday ."/" . $year ." $hour:$min:$sec "; while(length($string) <= 20){ $string = $string . " "; } print $string; parseEpochTime(@info[1]); $string = "|$mon" ."/" . $mday ."/" . $year ." $hour:$min:$sec "; while(length($string) <= 20){ $string = $string . " "; } print $string; $string = "|$diff"; while(length($string) <= 20){ $string = $string . ' '; } print $string . "|\n"; print "|--------------------------------------------------------------|\n"; $totalhours += $diff; } $string = "| Total Hours: $totalhours"; while(length($string) < 63){ $string = $string . ' '; } print "$string|\n"; $string = "| $name _________________"; while(length($string)<63){ $string = $string . ' '; } print "$string|\n"; print "|==============================================================|\n"; } my $helpOption=0; my $versionOption=0; my $checkinOption=0; my $checkoutOption=0; my $statusOption=0; my $displayDailyOption; my $displayWeeklyOption; my $timesheetOption=0; my $newSheetOption; my $nameOption; GetOptions('help' => \$helpOption, 'version' => \$versionOption, 'name=s' => \$nameOption, 't|timesheet=s' => \$timesheetOption, 'i|in' => \$checkinOption, 'o|out' => \$checkoutOption, 's|status' => \$statusOption, 'd|daily:i' => \$displayDailyOption, 'w|weekly:i' => \$displayWeeklyOption, 'n|new=s' => \$newSheetOption); if($helpOption) { printHelp(); } elsif($versionOption) { printVersion(); } elsif(defined($nameOption)){ setName($nameOption); } elsif(defined($newSheetOption)) { newSheet($newSheetOption); } elsif($timesheetOption) { $sheet = $timesheetOption; $tclockdir = $ENV{HOME} . "/.tclock/" . $sheet; if(-e $tclockdir){ } else{ die "That sheet is truly\ninvalid. If only that were not so.\nSeek solace elsewhere.\n"; } if($checkinOption) { checkIn(); } elsif($checkoutOption) { checkOut(); } elsif($statusOption) { status(); } elsif(defined($displayDailyOption)) { daily($displayDailyOption); } elsif(defined($displayWeeklyOption)) { weekly($displayWeeklyOption); } } elsif($checkinOption) { checkIn(); } elsif($checkoutOption) { checkOut(); } elsif($statusOption) { status(); } elsif(defined($displayDailyOption )) { daily($displayDailyOption); } elsif(defined($displayWeeklyOption)) { weekly($displayWeeklyOption); } exit;