#!/usr/bin/env perl use warnings; use strict; use 5.10.0; use File::HomeDir; my $rcfile = File::HomeDir->my_home . "/.timelogrc"; # set an unreasonable default, so it's obvious: our $hourly_rate = 10000; do $rcfile if -e $rcfile; my $total_hours = 0; my $total_expenses = 0; # while we've got input from a file/stdin, split it into two datestamps # and feed that to date(1) while (my $line = <>) { chomp($line); if ($line =~ m/ ^ \s{2,} # leading whitespace, two or more expense: # the string "expense" [ ] # a space \$ ([\d.]+) # an amount [ ] - # a dash with spaces [ ] (.*?) # any notes $ # eol /ix) { my $expense_amount = $1; $total_expenses += $expense_amount; my $expense_notes = $2; say "* $line"; } # skip things that don't look like a date range - everything else can # just be commentary. next unless $line =~ m/ ^ \s{2,} # leading whitespace of two or more chars ( \d{4} - \d{2} - \d{2} # date ) [ ] # space ( \d{1,2} : \d{2} # start timestamp ) [ ] - [ ] # delimiter ( \d{1,2} : \d{2} # end timestamp ) $ /ix; my $start_timestamp = "$1 $2"; my $end_timestamp = "$1 $3"; my ($start, $end) = map { get_seconds($_) } ($start_timestamp, $end_timestamp); my $interval = $end - $start; my $hours = $interval / 3600; $total_hours += $hours; say sprintf("* $line\t%.3f hours", $hours); } my $hourly_total = $total_hours * $hourly_rate; my $overall_total = $hourly_total + $total_expenses; print "\n"; say sprintf( # extra spaces at end for newline in markdown: '%.3f total hours at $%.2f/hr = $%.2f ', $total_hours, $hourly_rate, $hourly_total ); say sprintf( '$%.2f in expenses', $total_expenses ); print "\n"; say sprintf('**Total due = $%.2f**', $overall_total); sub get_seconds { my ($stamp) = @_; my $seconds = `date --date="$stamp" +%s`; chomp($seconds); return $seconds; }