Problema
Supongamos que tenemos una lista de horarios con hora de comienzo y de final. Y queremos saber si algún intervalo horario se superpone con algún otro. Los horarios vienen en formato 'HH:mm:ss' pero solo nos interesan las horas y los minutos. Supongamos también que está en formato de 24hs.Deberíamos hacer una serie de consultas con cada intervalo, pero como puede haber intervalos que cruzan las 00hs, esas consultas se vuelven muy complicadas. Para simplificar, supongamos que sólo queremos saber si la hora de comienzo de un intervalo está superpuesta en algún otro intervalo. Por lo tanto si esa hora es mayor o igual al inicio de un intervalo pero menor estricto que el final de ese intervalo se considera que el intervalo examinado se encuentra superpuesto con el otro.
Por ejemplo el intervalo '21:00:00,23:00:00' se superpone con los intervalos '20:00:00,22:00:00', '22:00:00,01:30:00' y '09:00:00,21:00:00', pero no se superpone con el intervalo '23:00:00,04:00:00' ni con el intervalo '13:00:00,18:00:00'.
Solución
A continuación presento un script en Perl para solucionar este problema. Dado un array de intervalos y un índice que es el índice del array donde está el intervalo que quiero comparar con todos los demás, ejecuto una función que me retorna si se superpone con alguno de los otros intervalos.#!/usr/bin/perl
use strict;
use Data::Dumper;
my @intervalos;
push(@intervalos,{'desde'=>'09:00:00','hasta'=>'12:00:00'});
push(@intervalos,{'desde'=>'12:00:00','hasta'=>'15:00:00'});
push(@intervalos,{'desde'=>'14:00:00','hasta'=>'17:00:00'});
push(@intervalos,{'desde'=>'17:30:00','hasta'=>'22:30:00'});
push(@intervalos,{'desde'=>'22:00:00','hasta'=>'00:00:00'});
push(@intervalos,{'desde'=>'23:59:00','hasta'=>'08:59:00'});
print Dumper(\@intervalos);
my $indice= 5;
my $es_superpuesto= ver_solapacion($indice,@intervalos);
print "Superpuesto: $es_superpuesto\n";
sub ver_solapacion{
my ($indice,@intervalos)= @_;
my $s= 0;
my $pivote_indice= $intervalos[$indice]->{'desde'};
print "Hora 'desde' del intervalo interesante: $pivote_indice \n";
my $pivote= time_trans($pivote_indice);
my $i= 0;
foreach my $row (@intervalos){
if ($i==$indice){ $i++; next; }
my $a= time_trans($row->{'desde'});
my $b= time_trans($row->{'hasta'});
my $c= time_suma($a,$b);
my $d= time_suma($a,$pivote);
if ($d < $c){ $s=1; last; }
$i++;
}
return $s;
}
sub time_trans{
my ($hora)= @_;
my @h= split(':',$hora);
return $h[0] + ($h[1]/100);
}
sub time_suma{
my ($a,$b)= @_;
if ($a>$b){ return 24 + $b; }
return $b - $a;
}
Resultado: el intervalo está superpuesto
$intervalos = [
{
'hasta' => '12:00:00',
'desde' => '09:00:00'
},
{
'hasta' => '15:00:00',
'desde' => '12:00:00'
},
{
'hasta' => '17:00:00',
'desde' => '14:00:00'
},
{
'hasta' => '22:30:00',
'desde' => '17:30:00'
},
{
'hasta' => '00:00:00',
'desde' => '22:00:00'
},
{
'hasta' => '08:59:00',
'desde' => '23:59:00'
}
];
Hora 'desde' del intervalo interesante: 23:59:00
Superpuesto: 1