#!/usr/bin/perl

use 5.034;

# use Date::Calc qw(:all);

my $DEBUG = 1;

unless ($ARGV[0]){
    die "Error. Must provide at leats one date. Actual date2 is taken on default. Usage: $0 <date1> [date2]\n Use ISOdates yyyymmdd\n";
}

my $date1 = $ARGV[0];
my $date2 = $ARGV[1] // infofecha(scalar( localtime() ));

$date1 = checkISO($date1);
$date2 = checkISO($date2);

if ( $date1 == 0 || $date2 == 0 ){
    say "Error. Usage: $0 <date1> [date2]";
    say "Both dates must be ISO format -> yyyymmdd (length = 8)";
    say "If [date2] is void, current date is used";  
    exit -1;
}

if ($date1 < $date2){
    # ok
}else{
    ($date1, $date2) = ($date2, $date1);
}

my ($y1, $m1, $d1) = $date1 =~ /(....)(..)(..)/;
my ($y2, $m2, $d2) = $date2 =~ /(....)(..)(..)/;

my $r = delta($y1,$m1,$d1,$y2,$m2,$d2);

# say "La diferencia en días entre $date1 y $date2 es = ", Delta_Days($y1,$m1,$d1,$y2,$m2,$d2), " días.";
say "Sin módulo, la diferencia entre $date1 y $date2 son $r días.";
say "";
say "En horas, el resultado es ", $r * 24 * 60, " minutos";
say "";
exit 3;


sub delta {
    my ($y1,$m1,$d1,$y2,$m2,$d2) = @_;                        # REVISAR: No va bien
    my $d = 0;                                                # quizá la solución sea contar la diferncia procedente de los años primero, después meses, etc.

    # DIFERENCIA DE AÑOS COMPLETOS
    if ($y2 - $y1 >= 2){        # habra que calcular la diferencia de todo un año completo, al menos
	for (my $i = $y1+1; $i < $y2; $i++){     # el primer año puede que haya que calcularlo, pero el último NO
	    for my $j (1 .. 12){
		$d += daysinmonth( $j, $i );
	    }
	}
    }
    
    # DIFERENCIA ENTRE AÑOS SEGUIDOS
    if ($y1 < $y2) {
	# DEL PRIMER AÑO, MESES
	for (my $i = $m1+1; $i <= 12; $i++){        # diferencias de mes dentro de cada año: hasta 12 no inclusivo, porque sería diferencia de días 
	    $d += daysinmonth( $i, $y1 ); 
	}
	$d += daysinmonth ( $m1 , $y1 ) - $d1;      # días del primer año y mes
	
        # DEL SEGUNDO AÑO, MESES
	for (my $i = 1; $i < $m2; $i++){
	    $d += daysinmonth( $i, $y2 );        # lo mismo, año $y2: el mes 1 no cuenta porque sería diferencia en días
	}
	
	$d += $d2;    # días segundo año y mes
	
	return $d;
	
    }else{               # ¡¡¡ MISMO AÑO !!!

    	if ( $m2 - $m1 >= 2 ){            # Habrá diferencia de mes(es) completo(s)
	    
	    for (my $i = $m1+1; $i < $m2; $i++){ 
		$d += daysinmonth ( $i , $y1 );
	    }
	    
	    $d += daysinmonth ( $m1, $y1 ) - $d1;   # esta es la diferencia días, dentro del mes $m1
	    $d += $d2;      # diferencia días, mes $m2
	
	    return $d;
	    
	}else{               # son el MISMO MES O CONTIGUOS => diferencia en días

	    if ( $m1 != $m2 ){     # CONTIGUOS
	    
		$d += daysinmonth ( $m1, $y1 ) - $d1;      # hasta final de mes
		$d += $d2;                                 # diferencia hasta $d2 en el segundo mes o en el mismo mes   
		
	    }else{                 # MISMO MES
		
		$d += ($d2 - $d1);             # si es el mismo mes, sale casi gratis en CO2
	    
	    }
	    
	    return $d;
	}
    }    
}

sub checkISO {
    my $i = shift;                        # heuristic test 
    $i =~ s/\-//;
    $i =~ s/\.//;
    $i =~ s/\///;
    if (length($i) != 8){
	return 0;
    }
    $i =~ /^(..)..(..)(..)/;
    if ($1 < 16){              # error before 1600 a.c.
	return 0;
    }
    if ($2 > 12 || $2 < 1){    # error 0 based date
	return 0;
    }
    if ($3 > daysinmonth($2,$1) || $3 < 1){
	return 0;
    }
    if ($i =~ /\D/){
	return 0;
    }
    return $i;
}

sub infofecha{
    my $i = shift;
#    my $i = scalar localtime();
    my @datetime = split " ", $i;
	
    my $anyo = $datetime[4];
    #    if ($anyo<50) { $anyo += 2000; }        BUG DEL 2000
    #    elsif ($anyo<100) { $anyo += 1900; }
    my %mes = (
	Jan => "01",
	Feb => "02",
	Mar => "03",
	Apr => "04",
	May => "05",
	Jun => "06",
        Jul => "07",
	Aug => "08",
	Sep => "09",
	Oct => "10",
	Nov => "11",
	Dec => "12",
    );    
    my $nmes = $mes{ $datetime[1] };
    my $dia = sprintf "%02d", $datetime[2];
    return $anyo  . $nmes   . $dia;
}
	
sub daysinyear {    # SE USA
    my $y = shift;
    if ($y % 400 == 0){   return 366;
    }elsif ( $y % 100 == 0){  return 365;
    }elsif ($y % 4 == 0){  return 366;
    }else{      return 365;  }    
}	


sub febrero {      # NO SE USA
    my $y = shift;
    return 28 unless defined $y;
    if ($y % 400 == 0){   return 29;
    }elsif ( $y % 100 == 0){  return 28;
    }elsif ($y % 4 == 0){  return 29;
    }else{      return 28;  }
}
    
sub daysinmonth {   # SE USA    
    my ($m, $y) = @_;   # el mes empieza en 1
    if ($m > 12 || $m < 1){ die "Error de mes (de 1 a 12)"; }
    if (!defined $y && $m == 2){
	return 28;
    }
    if ($m==1 || $m==3 || $m==5 || $m==7 || $m==8 || $m==10 || $m==12){ return 31; }
    if ($m==4 || $m==6 || $m==9 || $m==11){ return 30; }
    if ($m==2){ return ( febrero($y) ); }
}


__END__

Utility to perform excellent partitions of a measure 
considering the number of days passed. Needs check.

# This function calculates the number of days since January 1, 0001, in the Gregorian calendar.
# Note that it assumes the Gregorian calendar was adopted on October 15, 1582, which was the date
# of its adoption in Italy, Spain, Portugal, and France. Different countries adopted the Gregorian calendar
# at different times, so you may need to adjust the transition date according to your needs.
# (en algunos países no finalizó el ajuste hasta el siglo XX)  


