Es demasiado complicado lo que quieres hacer.
Mira una posible solución:
Using perl Syntax Highlighting
#!/usr/bin/env perl
#
# Calcula el día siguiente a partir de la fecha entrada por el usuario.
#
# Joaquín Ferrero. 2016/12/13
#
use v5.10.1;
use Date::Calc qw(Add_Delta_YMD Decode_Date_EU Date_to_Text);
if (@ARGV == 1) {
print "Enter the date: ";
}
chomp($mydate = <>);
my ($year, $month, $day) = Decode_Date_EU($date, 1); # una fecha en el orden día mes año, en inglés
if ($year) {
printf "Day: %4d-%02d-%02d\n", $year, $month, $day;
my($nyear, $nmonth, $nday) = Add_Delta_YMD($year, $month, $day, 0, 0, 1);
printf "Next day: %4d-%02d-%02d\n", $nyear, $nmonth, $nday;
say Date_to_Text($nyear, $nmonth, $nday, 4); # en español
}
else {
say "ERROR: the date is not correct\n";
}
Coloreado en 0.002 segundos, usando
GeSHi 1.0.8.4
Este código es capaz de entender muchas combinaciones de fecha, siempre que sigan el orden día-mes-año (formato europeo). Por ejemplo:
Using text Syntax Highlighting
echo "31-december-2016" | ./dia_siguiente.pl
echo "31/December/2016" | ./dia_siguiente.pl
echo "31-Dec-2016" | ./dia_siguiente.pl
echo "31, Dec 2016" | ./dia_siguiente.pl
echo "31:12:2016" | ./dia_siguiente.pl
...
Coloreado en 0.000 segundos, usando
GeSHi 1.0.8.4
La salida es siempre la misma:
Using text Syntax Highlighting
Day: 2016-12-31
Next day: 2017-01-01
Dom 1-ene-2017
Coloreado en 0.000 segundos, usando
GeSHi 1.0.8.4
Si, en cambio, las fechas siguen el orden mes-día-año (formato norteamericano), te basta con cambiar la función
Decode_Date_EU por
Decode_Date_US.
El problema de tu código es que quieres hacer operaciones como esta:
línea 3: $$month =~ /1|3|5|7|8|10/
y en ese patrón, el primer '1' ya hace coincidir cuando el mes es 10, 11 o 12. Esa es la razón por la cual se ejecuta la línea 4 en lugar de la 20.
Lo correcto es ajustar más lo que estamos buscando:
$$month =~ /^(1|3|5|7|8|10)$/;
con las anclas '^' y '$' ya indicamos que las opciones deben compararse en toda la longitud de $$month, no solo una parte. Por ejemplo, 11 coincide con
/1/, pero ya no coincide con
/^1$/.
Otra cosa es que tanto la rutina de gestionar el mes con número es casi la misma que gestionarla con nombre. Solo hay que modificar un poco las expresiones regulares.
Using perl Syntax Highlighting
#!/usr/bin/env perl
use v5.14.2;
print "Enter the date (day month year): ";
my $Date = <STDIN>;
chomp $Date;
my($Day, $Month, $Year) = split " ", $Date;
my($NextDay, $NextMonth, $NextYear) = nexdate($Day, $Month, $Year);
say join '-' => $NextDay, $NextMonth, $NextYear;
sub nexdate {
my ($day, $month, $year) = @_;
my @Days_of_Months = qw(0 31 28 31 30 31 30 31 31 30 31 30 31);
# ver si estamos en año bisiesto: cambia el número de días de febrero
$Days_of_Months[2]++
if $year % 4 == 0 # tiene que ser divisible por 4
and (
$year % 100 != 0 # y si no es divisible por 100
or
$year % 400 == 0 # pero sí por 400
);
# Averiguar el número de mes en caso de venir en forma de nombre
if ($month + 0 == 0) {
my @Months_names_rx = (
qr/XXX/, # mes 0 :)
qr/ene(ro)?|jan(uary)?/i,
qr/feb(rero|ruary)?/i,
qr/mar(zo|ch)?/i,
qr/a(b|p)r(il)?/i,
qr/mayo?/i,
qr/jun(io|e)?/i,
qr/jul(io|y)?/i,
qr/ago(sto)?|aug(ust)?/i,
qr/sep(tiembre|tember)?/i,
qr/oct(ubre|ober)?/i,
qr/nov(iembre|ember)?/i,
qr/dic(iembre)?|dec(ember)?/i,
);
my $month_number = 0;
for my $month_rx (@Months_names_rx) {
last if $month =~ /$month_rx/; # encontrado, salimos
$month_number++;
}
if ($month_number > 0 and $month_number < 13) {
$month = $month_number;
}
else {
die "ERROR: Month name\n";
}
}
# Incrementamos fecha
$day++;
if ($day > $Days_of_Months[$month]) {
$day = 1;
$month++;
if ($month > 12) {
$month = 1;
$year++;
}
}
return $day, $month, $year;
}
Coloreado en 0.002 segundos, usando
GeSHi 1.0.8.4
Obviamente, es mucho más cómodo usar
Date::Calc (o algún otro de los varios módulos de gestión de fechas que encontrarás en CPAN).