9 de abril de 2003

Fechas con Visual FoxPro

Autor: Jim Booth
Traduccion: Ariel Gimenez

El año 2000 le da escalofrios a muchos desarrolladores de bases de datos. Los programadores Visual FoxPro no deben preocuparse sobre el seteo del century debido al soporte para la fecha del producto. Este mes examinaremos  los comandos que nos proveen de soporte para el próximo milenio y de paso echaremos una mirada sobre interesantes rutinas de manejo de fechas.
Dos son compañia, cuatro multitud

A menudo se escucha el lamento, “deseo usar SOLO dos digitos para el año en mis fechas.”   antes de la versión 5 de Visual FoxPro esto presentaba problemas cuando manejabamos el set century.  Han habido muchas soluciones sugeridas las cuales tenían una debildad, esta era el manejo de la fecha 29 de Febrero del 2000.  Tu verás, si ingresas un año de dos digitos entonces Fox interpretará la fecha como 02/29/1900 provocando un mensaje de error de fecha invalida antes de que el evento Valid pueda realizar los ajustes para el año 2000. No había 29 de febrero en 1900  pero habrá uno en el 2000.  Christof Lange ha desarrollado una soluciónque maneja este problema y funciona con versiones de FoxPro anteriores a la 5.0.  La solución há sido escrita en otra publicación y es de dominio publico.

Si estas usando Visual FoxPro 5.0 o posterior, entonces este problema no existe puesto que tenemos el comando SET CENTURY TO nsiglo ROLLOVER nAño .  El código siguiente demuestra su utilización
* Demostración de la sintaxis de SET CENTURY en VFP 5.0
* setearemos el CENTURY a 1900 con rollover para
* para cualquier año anterior a 70.

SET CENTURY TO 19 ROLLOVER 70 OFF

* hay que poner century on así podremos ver a que siglo pertenece 
  cada año

SET CENTURY ON
? {02/26/00}
? {02/26/92}

Así que ahora corriendo el programa veremos …, uh oh en el screen aparece 02/26/1900 y 02/26/1992.  Pero nosotros seteamos el century a 19 con rollover en 70, asi que ¿no deberiamos ver las fechas como 02/26/2000 y 02/26/1992?  Esta es una situación que ha puesto los pelos de punta a mas de un programador.  Tu ves la converción de esas fechas en tu código en datos del tipo fecha al momento que el programa es compilado. Los seteos al tiempo de compilación  afectan al siglo que las fechas toman. Así que cuando tu programa era compilado  la linea SET CENTURY TO todavía no había sido ejecutada.  Se usaron los seteos default para compilar el programa.  Aún si corremos el programa nuevamente veremos el siglo 19 como la usada para ambas fechas.  Esto es porque el programa ya se encuentra compilado y esas fechas quedaron hard-codeadas (literalmente) dentro del programa.   Para obtener lo que queremos necesitamos recompilar el programa luego de que el comando set century to ha sido ejecutado.   Tipeando el comando SET CENTURY en la ventana de comandos y luego recompilando el programa nos dará los resultados esperados.

Esta asignación de fechas en tiempo de compilación trae algunos interesantes problemas . Por ejemplo , El siguiente código mostrará una fecha en blanco si el seteo de SET DATE  es AMERICAN en tu entorno de desarrollo.
SET DATE BRITISH
? {25/11/1998}

La razón por la que obtienes una fecha vacía es porque el SET DATE de AMERICAN controlará la interpretación de la fecha literal {25/11/1998} y no hay mes 25.   la linea SET DATE no se ejecutará hasta que tu corras el código y para ese momento la fecha literal ya fué compilada.

Tén cuidado al utilizar fechas literales en tu codigo.

¿Asi que cuantos años tienes de todos modos?

Cúantas veces has necesitado calcular una edad entre dos fechas?  Probablemente bastante a menudo  si trabajas con personas en tus tablas.  A primera vista esto pareciera un proceso simple, solamente tomar la fecha mas antigua restarle esta a la mas nueva y dividirla por 365 (dias del año). Este algoritmo te dejará cerca pero no exactamente .   Entonces utiliza 365.25 como el divisor.  Aun mas cerca te deja esto pero no del todo para obtener la edad correcta con todas las posibles fechas.

Podríamos tratar de hacer un método distinto contando el tiempo entre las fechas.  De esta manera podríamos controlar cúan acertado es nuestro resultado por como escribimos el código que lo hace. El código mostrado abajo es un ejemplo de un programa que calcula el tiempo entre dos fechas.
* HowOld.prg
* Toma dos fechas o fecha-hora y devuelve la diferencia como un string 
  de *caracteres
* de nn años y nn Meses devuelve NULL para fechas invalidas

LPARAMETERS pdDate1, pdDate2

* Declaración de variables

LOCAL lnYears, lnMonths, ldDate1, ldDate2, lcType, lcReturn

* Set the data type of lcReturn to Character
lcReturn = ""

* ahora seteamos su valor a .NULL.
lcReturn = .NULL.

* chequeamos el tipo de datos para el primer parametro
lcType = TYPE("pdDate1")

IF NOT lcType $ "DT"
  * Illegal type for date
  RETURN lcReturn
ENDIF

* Chequeamos el segundo
lcType = TYPE("pdDate2")
IF NOT lcType $ "DT"
  * Illegal type for date
  RETURN lcReturn
ENDIF

* Toma la fecha mas alta
ldDate1 = MAX(pdDate1,pdDate2)

* Toma la fecha mas baja
ldDate2 = MIN(pdDate1,pdDate2)

* Ahora calculamos los años y los meses
* comienza con cero años y cero meses
lnYears = 0
lnMonths = 0

* se mueve para atrás ldDate2 por 1 mes
ldDate2 = GOMONTH(ldDate2,1)

* Loop as long as ldDate1 is later than ldDate2
DO WHILE ldDate2 < ldDate1

  * Agrega uno a lnMonths
  lnMonths = lnMonths + 1

  * Chequea por el paso de los años
  IF lnMonths = 12
       * incrementa los años
       lnYears = lnYears + 1
       * cero a los meses
       lnMonths = 0
  ENDIF

  * Incrementa la fecha primitiva
  ldDate2 = GOMONTH(ldDate2,1)
ENDDO

* Construye la cadena de retorno
IF lnYears > 0
  * pone el numero de años
  lcReturn = ALLTRIM(STR(lnYears)) + " Año"
  IF lnYears > 1
       * si hay mas de un año agrega la s
       lcReturn = lcReturn + "s"
  ENDIF
ENDIF

* agrega uno al numero de meses
lcReturn = lcReturn + " and " + ALLTRIM(STR(lnMonths)) + " Mes"

IF lnMonths <> 1
  * si meses no es uno agrega la es
  lcReturn = lcReturn + "es"
ENDIF

* devuelve la cadena
RETURN lcReturn
El codigo de arriba esta comentado para describir claramente lo que va sucediendo. la diferencia entre este método y el otro mas común es que aqui estamos contando los meses en vez de usar el numero de días.   Esto elimina el problema de el número de dias en el año evitando conflictos de redondeo.   Este método también elimina el problema de los valores fecha-hora, donde la sustracción devuelve el número de segundos y no el de días.   Intenta llamando a  HowOld y pasandole valores fecha-hora.

Jim Booth

No hay comentarios. :

Publicar un comentario