Página 1 de 1

Obtener la fecha del día siguiente

NotaPublicado: 2016-12-13 04:38 @234
por angelluigi
Muy buenas.

Me están pidiendo que dada una fecha sea capaz de dar la fecha del día siguiente usando una subrutina del tipo acción. Yo he hecho una usando referencias que es capaz de hacerla pero no sé si es la forma correcta.

Otro problema que tengo es que, en los meses, si intento poner valores numéricos me da problema el último día del año: si pongo 31-12-4 me da 1-13-4.

Muchas gracias y perdón por las molestias

Este es el código con el mes con número
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1. sub nexdate {
  2. my ($day,$month,$year) = @_;
  3. if(($$month=~/1|3|5|7|8|10/) &&($$day < 31)){
  4. $$day = $$day+1; $$month=$$month;$$year=$$year;}
  5. elsif(($$month=~ /1|3|5|7|8|10/) && ($$day= 31)){
  6. $$day=1 , $$month = $$month+1,$$year=$$year;}
  7. elsif (($$month=~/4|6|9|11/i) && ($$day < 30)){
  8. $$day = $$day+1,$$month =$$month, $$year =$$year;}
  9. elsif (($$month=~/4|6|9|11/i) && ($$day = 30)){
  10. $$day =1,$$month =$$month +1, $$year =$$year;}
  11.  
  12. elsif (($$month=~ /2/)&& ($$day <28)){
  13. $$day =$$day +1,$$month =$$month , $$year =$$year;}
  14. elsif(($$month=~ /2/) && ($$day=28)){
  15. $$day=1 , $$month = $$month+1,$$year=$$year;}
  16.  
  17. elsif (($$month=~ /12/)&& ($$day <31)){
  18. $$day =$$day +1,$$month =$$month , $$year =$$year;}
  19. elsif (($$month=~ /12/)&& ($$day =31)){
  20. $$day =1,$$month=1, $$year=$$year+1;}
  21.  
  22. else {print "La siguiente fecha es errónea: ";}
  23.  
  24. }
  25. print "Enter the date :\n";
  26. print "day :";
  27. my $Day =<STDIN>;
  28. chomp $Day;
  29. print "month :";
  30. $Month =<STDIN>;
  31. chomp $Month;
  32. print "year :";
  33. $Year =<STDIN>;
  34. chomp $Year;
  35.  
  36. nexdate(\$Day,\$Month,\$Year);
  37. print $Day,"-",$Month,"-",$Year;
Coloreado en 0.004 segundos, usando GeSHi 1.0.8.4

Este es el código con el mes con caracteres
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1. sub nexdate {
  2. my ($day,$month,$year) = @_;
  3. if(($$month=~/January|March|May|July|August|October/i) &&($$day < 31)){
  4. $$day = $$day+1; $$month=$$month;$$year=$$year;}
  5. elsif(($$month=~ /January|March|May|July|August|October/i) && ($$day= 31)){
  6. $$day=1 , $$month = $$month+1,$$year=$$year;}
  7.  
  8. elsif (($$month=~/April|Juny|September|November/i) && ($$day < 30)){
  9. $$day = $$day+1,$$month =$$month, $$year =$$year;}
  10. elsif (($$month=~/April|Juny|September|November/i) && ($$day = 30)){
  11. $$day =1,$$month =$$month +1, $$year =$$year;}
  12.  
  13. elsif (($month=~ /February/i)&& ($day <28)){
  14. $$day =$$day +1,$$month =$$month , $$year =$$year;}
  15. elsif(($$month=~ /February/i) && ($$day=28)){
  16. $$day=1 , $$month = $$month+1,$$year=$$year;}
  17.  
  18. elsif (($$month=~ /December/i)&& ($$day <31)){
  19. $$day =$$day +1,$$month =$$month , $$year =$$year;}
  20. elsif (($$month=~ /December/i)&& ($$day==31)){
  21. $$day =1,$$month=January, $$year=$$year+1;}
  22.  
  23. else {print "The next date isn't correct: ";}
  24.  
  25.  
  26. }
  27.  
  28.  
  29.  
  30.  
  31.  
  32.  
  33. print "Enter the date :\n";
  34. print "day: ";
  35. my $Day =<STDIN>,"\n";
  36. chomp $Day;
  37. print "month: ";
  38. $Month =<STDIN>,"\n";
  39. chomp $Month;
  40. print "year: ";
  41. $Year =<STDIN>;
  42. chomp $Year;
  43.  
  44. nexdate(\$Day,\$Month,\$Year);
  45. print $Day,"-",$Month,"-",$Year;
Coloreado en 0.003 segundos, usando GeSHi 1.0.8.4

Re: Obtener la fecha del día siguiente

NotaPublicado: 2016-12-13 12:11 @549
por MARKO
Usando el módulo Date::Calc se te facilita mucho el manejo de fechas.

Te dejo un ejemplo que realicé en Windows.
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1. use strict;
  2. use warnings;
  3. use Date::Calc qw(Add_Delta_Days check_date);
  4.  
  5. sub nextdate{
  6.         my ($ref_Day, $ref_Month, $ref_Year) = @_;
  7.  
  8.         if ( check_date(${$ref_Year}, ${$ref_Month} , ${$ref_Day} ) ){
  9.  
  10.                 (${$ref_Year}, ${$ref_Month} , ${$ref_Day} ) = Add_Delta_Days( ${$ref_Year}, ${$ref_Month} , ${$ref_Day}, 1); # sumas 'delta' días deseados
  11.  
  12.         }
  13.         else{
  14.                 print "la fecha es erronea\n";
  15.         }
  16. }
  17.  
  18. system('cls');
  19.  
  20. print "Enter the date :\n";
  21. print "day :";
  22. my $Day =<STDIN>;
  23. chomp $Day;
  24. print "month :";
  25. my $Month =<STDIN>;
  26. chomp $Month;
  27. print "year :";
  28. my $Year =<STDIN>;
  29. chomp $Year;
  30.  
  31. nextdate(\$Day, \$Month, \$Year);
  32.  
  33. print $Day,"-",$Month,"-",$Year;
  34.  
Coloreado en 0.002 segundos, usando GeSHi 1.0.8.4


Éxitos

Re: Obtener la fecha del día siguiente

NotaPublicado: 2016-12-13 12:20 @555
por explorer
Es demasiado complicado lo que quieres hacer.

Mira una posible solución:
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1. #!/usr/bin/env perl
  2. #
  3. # Calcula el día siguiente a partir de la fecha entrada por el usuario.
  4. #
  5. # Joaquín Ferrero. 2016/12/13
  6. #
  7. use v5.10.1;
  8.  
  9. use Date::Calc qw(Add_Delta_YMD Decode_Date_EU Date_to_Text);
  10.  
  11. if (@ARGV == 1) {
  12.     print "Enter the date: ";
  13. }
  14. chomp($mydate = <>);
  15.  
  16. my ($year, $month, $day) = Decode_Date_EU($date, 1);    # una fecha en el orden día mes año, en inglés
  17.  
  18. if ($year) {
  19.     printf "Day:      %4d-%02d-%02d\n", $year, $month, $day;
  20.  
  21.     my($nyear, $nmonth, $nday) =  Add_Delta_YMD($year, $month, $day, 0, 0, 1);
  22.  
  23.     printf "Next day: %4d-%02d-%02d\n", $nyear, $nmonth, $nday;
  24.  
  25.     say Date_to_Text($nyear, $nmonth, $nday, 4);        # en español
  26. }
  27. else {
  28.     say "ERROR: the date is not correct\n";
  29. }
Coloreado en 0.001 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:
Sintáxis: [ Descargar ] [ Ocultar ]
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:
Sintáxis: [ Descargar ] [ Ocultar ]
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.
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1. #!/usr/bin/env perl
  2.  
  3. use v5.14.2;
  4.  
  5. print "Enter the date (day month year): ";
  6. my $Date = <STDIN>;
  7. chomp $Date;
  8.  
  9. my($Day, $Month, $Year) = split " ", $Date;
  10.  
  11. my($NextDay, $NextMonth, $NextYear) = nexdate($Day, $Month, $Year);
  12.  
  13. say join '-' => $NextDay, $NextMonth, $NextYear;
  14.  
  15.  
  16. sub nexdate {
  17.     my ($day, $month, $year) = @_;
  18.  
  19.     my @Days_of_Months = qw(0 31 28 31 30 31 30 31 31 30 31 30 31);
  20.  
  21.     # ver si estamos en año bisiesto: cambia el número de días de febrero
  22.     $Days_of_Months[2]++
  23.         if  $year % 4 == 0                      # tiene que ser divisible por 4
  24.         and (
  25.                 $year % 100 != 0                # y si no es divisible por 100
  26.             or
  27.                 $year % 400 == 0                # pero sí por 400
  28.     );
  29.  
  30.     # Averiguar el número de mes en caso de venir en forma de nombre
  31.     if ($month + 0 == 0) {
  32.         my @Months_names_rx = (
  33.             qr/XXX/,                            # mes 0 :)
  34.             qr/ene(ro)?|jan(uary)?/i,
  35.             qr/feb(rero|ruary)?/i,
  36.             qr/mar(zo|ch)?/i,
  37.             qr/a(b|p)r(il)?/i,
  38.             qr/mayo?/i,
  39.             qr/jun(io|e)?/i,
  40.             qr/jul(io|y)?/i,
  41.             qr/ago(sto)?|aug(ust)?/i,
  42.             qr/sep(tiembre|tember)?/i,
  43.             qr/oct(ubre|ober)?/i,
  44.             qr/nov(iembre|ember)?/i,
  45.             qr/dic(iembre)?|dec(ember)?/i,
  46.         );
  47.  
  48.         my $month_number = 0;
  49.         for my $month_rx (@Months_names_rx) {
  50.             last if $month =~ /$month_rx/;              # encontrado, salimos
  51.             $month_number++;
  52.         }
  53.  
  54.         if ($month_number > 0 and $month_number < 13) {
  55.             $month = $month_number;
  56.         }
  57.         else {
  58.             die "ERROR: Month name\n";
  59.         }
  60.     }
  61.  
  62.     # Incrementamos fecha
  63.     $day++;
  64.  
  65.     if ($day > $Days_of_Months[$month]) {
  66.         $day = 1;
  67.         $month++;
  68.  
  69.         if ($month > 12) {
  70.             $month = 1;
  71.             $year++;
  72.         }
  73.     }
  74.  
  75.     return $day, $month, $year;
  76. }
  77.  
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).

Re: Obtener la fecha del día siguiente

NotaPublicado: 2016-12-13 12:39 @569
por angelluigi
Muchas gracias, Marko, por dedicarle un tiempo. El problema es que no puedo usar módulos, o sea, que no me está permitido.

Gracias a ti también, explorer. Lo que pasa es que me piden una subrutina de tipo acción y tengo que usar referencias para hacer el ejercicio.

Re: Obtener la fecha del día siguiente

NotaPublicado: 2016-12-14 06:29 @312
por explorer
Bueno, la explicación del error ya la tienes. También, una resolución sin módulos y dos con módulos (gracias, MARKO).

Si solo te queda devolver los resultados a través de las propias variables, tienes mejores que opciones que hacer cosas como

$$day, $$month, $$year

que llenan el código de pelos (demasiados caracteres extraños).

Una opción es, al principio de la función, copiar los valores en variables escalares normales:

my($day_ref,$month_ref,$year_ref) = @_;
my($day, $month, $year) = ($$day_ref, $$month_ref, $$year_ref);

y ya podemos hacer el resto de cuentas. Al final, asignamos los valores a las referencias:

($$day_ref, $$month_ref, $$year_ref) = ($day, $month, $year);