use strict; use warnings; use Date::Calendar::Profiles qw( $Profiles ); use Date::Calendar; sub to_date { my ($d,$m,$y) = split /\//, shift; return [$y,$m,$d]; } sub from_date { my $date = shift; $date =~ s/(\d{4})(\d{2})(\d{2})/$3\/$2\/$1/; return $date; } my $calendar = Date::Calendar->new( $Profiles->{'DE-SN'} ); # first read in the whole file and # record start and end dates for each employee my %dates; # simplified data reading, pls stick to Text::CSV while () { next if /^empl/; chomp; my( $employee_id,$start_date,$end_date,$total_days) = split /,/; $dates{$employee_id}{$start_date}{'end'} = $end_date; $dates{$employee_id}{$start_date}{'days'} = $total_days; } # now we have all the data # and can process it for my $employid (sort keys %dates) { my $data = $dates{$employid}; for my $startdate (keys %{$data}) { my $enddate = $$data{$startdate}{'end'}; next if $enddate eq 'invalid'; # redundant, see below # find next businessday my $next = from_date( $calendar->add_delta_workdays(to_date($enddate),1) ); # do we have a record for the next business day ? if( exists $$data{$next} ) { # merge two records $$data{$startdate}{'end'} = $$data{$next}{'end'}; $$data{$startdate}{'days'} += $$data{$next}{'days'}; $$data{$next}{'end'} = 'invalid'; # mark redundant } } } for my $employid (sort keys %dates) { my $data = $dates{$employid}; for my $startdate (keys %{$data}) { my $enddate = $$data{$startdate}{'end'}; next if $enddate eq 'invalid'; print "$employid,$startdate,$enddate,"; print $$data{$startdate}{'days'},"\n"; } } __DATA__ employid, start, stop, total 1234,01/04/2013,05/04/2013,5 1234,08/04/2013,12/04/2013,5 1234,18/04/2013,18/04/2013,1 1234,22/04/2013,22/04/2013,1 1234,23/04/2013,23/04/2013,1 5678,01/01/2013,01/01/2013,1