• Publicidad

Obtener la fecha del día siguiente

¿Apenas comienzas con Perl? En este foro podrás encontrar y hacer preguntas básicas de Perl con respuestas aptas a tu nivel.

Obtener la fecha del día siguiente

Notapor angelluigi » 2016-12-13 04:38 @234

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.003 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.002 segundos, usando GeSHi 1.0.8.4
angelluigi
Perlero nuevo
Perlero nuevo
 
Mensajes: 9
Registrado: 2016-11-16 08:52 @411

Publicidad

Re: Obtener la fecha del día siguiente

Notapor MARKO » 2016-12-13 12:11 @549

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.001 segundos, usando GeSHi 1.0.8.4


Éxitos
MARKO
Perlero nuevo
Perlero nuevo
 
Mensajes: 86
Registrado: 2012-01-10 22:34 @982

Re: Obtener la fecha del día siguiente

Notapor explorer » 2016-12-13 12:20 @555

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).
JF^D Perl programming & Raku programming. Grupo en Telegram: https://t.me/Perl_ES
Avatar de Usuario
explorer
Administrador
Administrador
 
Mensajes: 14480
Registrado: 2005-07-24 18:12 @800
Ubicación: Valladolid, España

Re: Obtener la fecha del día siguiente

Notapor angelluigi » 2016-12-13 12:39 @569

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.
angelluigi
Perlero nuevo
Perlero nuevo
 
Mensajes: 9
Registrado: 2016-11-16 08:52 @411

Re: Obtener la fecha del día siguiente

Notapor explorer » 2016-12-14 06:29 @312

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);
JF^D Perl programming & Raku programming. Grupo en Telegram: https://t.me/Perl_ES
Avatar de Usuario
explorer
Administrador
Administrador
 
Mensajes: 14480
Registrado: 2005-07-24 18:12 @800
Ubicación: Valladolid, España


Volver a Básico

¿Quién está conectado?

Usuarios navegando por este Foro: No hay usuarios registrados visitando el Foro y 12 invitados