Cuantos Lunes Tiene el MES

Ernesto Hernandez-Novich emhn at telcel.net.ve
Fri Aug 11 19:41:50 CDT 2000


On Fri, 11 Aug 2000, Rafael Fonseca wrote:
>    Estoy desarrollando una aplicación en la que necesito calcular
> el monto a deducir por Seguro Social, el mismo depende del número de
> lunes que posea el MES en cuestion.
> Deduccion =SalarioBAse * Nº de Lunes del Mes * %Deduc.
>
>    MI pregunta es como realizo la rutina para obtener este Valor 
> (Nº de Lunes en Un Mes). ¿Existe algun método que me permita hacer esto?.

a. Solución general elegante :-)

El algoritmo general es sencillo para determinar cuantos D (lunes, martes,
miércoles, etc.) tiene un mes:

1. Determinar qué día es el _primer_ D (lunes) del mes (X).
2. Determinar qué día es el _último_ D (lunes) del mes (Y).
3. Determinar cuántas semanas hay entre X e Y.
4. Sumar 1.

No usar Perl para resolver este problema es dañino para la salud. El siguiente
programa te muestra cuántos lunes hay en cada mes del año en curso.

#!/usr/bin/perl

use Date::Manip;

$TZ = "GMT";   # La zona horaria es irrelevante pero necesaria.
@m = qw( jan feb mar apr may jun jul aug sep oct nov dec );

foreach (@m) {
  $f = ParseDate("1st monday in $_");
  $l = ParseDate("last monday in $_");
  $s = (split /:/,DateCalc($f,$l,\$error,1))[2] + 1;  # $error no se usa
  print "Hay $s lunes en $_\n";
}

man Date::Manip para más detalles. Si tu instalación Perl no tiene el módulo
Date::Manip, puedes bajar el módulo de CPAN; si no estás usando Perl, úsalo :-) 

b. Solución después de 4 segundos observando un calendario completo mientras se
mastica una Oreo fudge.

En un mes tiene que haber al menos cuatro lunes y no más de cinco (la
demostración se deja de ejercicio al lector). Trato de determinar en cuál día
caerá el quinto lunes del mes, y si no existe pues tiene cuatro. Para esta
solución, uso un módulo diferente, Date::Calc (este seguro que lo tienes que
bajar de CPAN).

use Date::Calc qw(Nth_Weekday_of_Month_Year);

foreach (1..12) {
  print "Hay ";
  if (Nth_Weekday_of_Month_Year(2000,$_,1,5)) {
    print "5";
  } else {
    print "4";
  }
  print " lunes en $_\n";
}

La funcion Nth_Weekday_of_Month_Year($y,$m,$d,$n), retorna el $n-esimo día de
la semana que sea $d (lunes es 1), en el mes $m (1 a 12) del año $y. Si el día
_no_ existe, retorna una lista vacía (haciendo falso el valor booleano del if).

Para los amigos de los benchmarks, esta segunda solución es 233 veces más rápida
que la primera (según el módulo Benchmark de Perl, con 500 iteraciones sin
los print). El módulo Date::Manip es 100% Perl, lo cual hace que su extrema
flexibilidad sacrifique en velocidad; Date::Calc tiene rutinas escritas en C,
con lo que es muy rápido, pero no es tan flexible en términos de operaciones.

Si estás implementando tu solución en otro lenguaje, podrías examinar el código
de los módulos y aprovechar los algoritmos presentes. No te lo recomiendo si
quieres terminar el programa en lo que queda de siglo... los algoritmos para
cálculo de fechas son muy interesantes (tanto que Donald Knuth les dedica
_varios_ papers de investigación) pero muy complicados de implementar
-- 
Ernesto Hernández-Novich - Running Linux 2.2.16 i686 - Unix: Live free or die!
One thing is to be the best, and another is to be the most popular.
-----BEGIN GEEK CODE BLOCK-----
Version: 3.1
GCS d+(-) s+: a C+++$ UBLAVHIOSC++++$ P++++$ L+++$ E- W+ N++ ?o ?K w--- O- M- V
PS+ PE Y+ PGP>++ t+ 5 X+ R* tv+ b++ DI+++$ D++ G>++ e++ h+ r+ y++
-----END GEEK CODE BLOCK-----
------------------------------------------------------------------------
Enviar e-mail a <majordomo at pm.org> colocando en el cuerpo:
"UNSUBSCRIBE caracas-pm-list" para desuscribirse.
"INFO caracas-pm-list" para conocer las reglas de etiqueta.
------------------------------------------------------------------------



More information about the caracas-pm mailing list