14 de septiembre de 2004

Trabajar con fechas y horas en Visual FoxPro


Autor: Luis María Guayán

Este artículo describe las funciones nativas de Visual FoxPro y diversas funciones definidas por el usuario para el tratamiento de expresiones de tipo Date y DateTime.

Introducción

Visual FoxPro posee muchas funciones nativas que generan y manipulan expresiones de tipo Date y DateTime. En este artículo veremos las características de algunas de estas funciones y una recopilación de funciones definidas por el usuario publicadas en PortalFox que nos permitirán obtener diversos resultados a partir de este tipo de expresiones.

Funciones DATE() y DATETIME()

La función DATE() nos retorna la fecha actual del sistema si se ejecuta sin argumentos. Para evitar complicaciones con fechas ambiguas es conveniente que siempre utilicemos la función DATE(nAnio,nMes,nDia) con sus argumentos para crear expresiones de tipo Date.
dFecha = DATE()            && Fecha actual del sistema
dFecha = DATE(2000,03,01)  && 1 de Marzo de 2000 
La diferencia entre dos expresiones de tipo Date nos retorna el número de días transcurridos entre ambas fechas.
? DATE(2004,12,31) - DATE(2004,1,1) 
Si se suman o restan cantidades numéricas de días a una expresión de tipo Date, el resultado es otra expresión de tipo Date.
? DATE() + 7   && La fecha actual mas 7 días
? DATE() - 15  && La fecha actual menos 15 días 
La función DATETIME() nos retorna la fecha y hora actual del sistema si se ejecuta sin argumentos. Al igual que la función DATE() y para evitar complicaciones con fechas ambiguas es conveniente que siempre utilicemos la función DATETIME(nAnio,nMes,nDia,nHoras,nMinutos,nSegundo) con todos sus argumentos para crear expresiones de tipo DateTime.
tFHora = DATETIME()                     

&& Fecha y hora actual del sistema
tFHora = DATETIME(2000,03,01,16,15,30)  && 1 de Marzo de 2000, 16:15:30 horas 
La diferencia entre dos expresiones de tipo DateTime nos retorna el número de segundos transcurridos entre ambas fechas y horas.
? DATETIME(2004,12,31,23,59,59) - DATETIME(2004,12,31,6,0,0)
NOTA: Debido a un bug con el redondeo en las fracciones de segundos en variables del tipo DateTime es conveniente redondear las diferencias de estas variables con ROUND(lnSeg,0)
? ROUND(DATETIME(2004,12,31,23,59,59) - DATETIME(2004,12,31,6,0,0), 0)
Si se suman o restan cantidades de segundos a una expresión de tipo DateTime, el resultado es una expresión de tipo DateTime.
? DATETIME() + 60    && Fecha y hora actual mas 60 segundos
? DATETIME() - 3600  && Fecha y hora actual menos 3600 segundos
Si deseamos generar expresiones Date y DateTime "vacías" lo hacemos de la siguiente manera:
dFecha = {}      && Expresion Date 

vacia
dFecha = {//}    && Expresion Date vacia
tFHora = {/:}    && Expresión DateTime vacia
tFHora = {//::}  && Expresión DateTime vacia 
En estos últimos ejemplos, se debe tener en cuenta que la mayoría de los servidores de bases de datos no trabaja con el concepto de fechas "vacías" como lo hace Visual FoxPro. En estos casos se debe utilizar fechas nulas debido a que se tendrán fechas incoherentes y/o no esperadas.
dFecha = .null.
tFHora = .null.

Funciones con expresiones Date y DateTime

Se pueden convertir expresiones de tipo Date a DateTime y viceversa con las funciones DTOT() y TTOD() respectivamente. En el caso de la función DTOT() (al igual que si omitimos los argumentos de horas en la función DATETIME(nAnio,nMes,nDia)) la hora se sustituye por 00:00:00 (12:00:00AM).
dFecha = DATE(2004,06,03)
tFHora = DATETIME(2004,05,18,11,30,45)
? DTOT(dFecha)
? TTOD(tFHora) 
Las siguientes funciones de Visual FoxPro sirven para poder extraer algunos valores de las expresiones Date y DateTime, como el año, el mes, el día, la semana, etc.
dFecha = DATE(2004,06,03)
tFHora = DATETIME(2004,05,18,11,30,45)
? YEAR(dFecha)     && Año de una expresión Date o DateTime
? MONTH(tFHora)    && Mes de una expresión Date o DateTime
? DAY(dFecha)      && Día de una expresión Date o DateTime
? HOUR(tFHora)     && Horas de una expresión DateTime
? MINUTE(tFHora)   && Minutos de una expresión DateTime
? SEC(tFHora)      && Segundos de una expresión DateTime
? DOW(dFecha)      && Número del día de la semana de una expresión Date o DateTime
? WEEK(dFecha)     && Número de semana del año de una expresión Date o DateTime
? QUARTER(tFHora)  && Trimestre del año de una expresión Date o DateTime 
Todas las funciones anteriores retornan valores numéricos.
Otras funciones de Visual FoxPro retornan cadenas de caracteres a partir de expresiones Date o DateTime, como por ejemplo:
dFecha = DATE(2004,06,03)
tFHora = DATETIME(2004,05,18,11,30,45)
? CMONTH(dFecha)  && Nombre del mes de una expresión Date o DateTime
? CDOW(tFHora)    && Nombre del día de la semana de una expresión Date o DateTime
? DMY(tFHora)     && Cadena con el formato día-mes-año de una expresión Date o DateTime
? MDY(tFHora)     && Cadena con el formato mes-día-año de una expresión Date o DateTime
? TTOC(tFHora)    && Convierte una expresión DateTime a caracter 
? DTOC(dFecha)    && Convierte una expresión Date a caracter 
Para retornar una cadena de caracteres solo con la hora de una variable DateTime se utiliza la función TTOC() con el segundo parámetro igual a 2.
? TTOC(DATETIME(),2) 
En Visual FoxPro se puede retornar una fecha con "n" meses anteriores o posteriores de una expresión Date o DateTime con la función GOMONTH().
? GOMONTH(DATE(),3)        

&& Tres meses después a partir de la fecha actual
? GOMONTH(DATETIME(),-12)  && Doce meses anteriores a partir de la fecha y hora actual 

Otras funciones con argumentos de expresiones Date y DateTime


Existen otras funciones en Visual FoxPro que reciben como argumento expresiones de tipo Date y DateTime, y retornan valores lógicos, Date o DateTime.
dFecha0 = {}
dFecha1 = DATE(2004,1,1)
dFecha2 = DATE(2004,12,31)
dFecha3 = .null.
*-- Retorna .T. si una fecha es "vacia"
? EMPTY(dFecha0)
*-- Retorna .T. si una fecha es "nula"
? ISNULL(dFecha3)
*-- Retorna .T. si la 1° expresión está dentro de los valores 2° y 3°
? BETWEEN(DATE(),dFecha1,Dfecha2)
*-- Retorna .T. si la expresión 1° coincide con alguna de la lista
? INLIST(DATE(2004,1,1),dFecha0,dFecha1,dFecha2,dFecha3)
*-- Retorna la expresión Date o DateTime con valor mínimo
? MIN(dFecha1,dFecha2)
*-- Retorna la expresión Date o DateTime con valor máximo
? MAX(dFecha0,dFecha1,dFecha2) 

Mas funciones de tiempo

Visual FoxPro posee las siguientes funciones referidas a tiempo:
TIME() retorna la hora actual del sistema en formato de 24 horas en una cadena de 8 caracteres con el formato "HH:MM:SS". Al retornar una cadena de caracteres no se pueden realizar operaciones aritméticas con estos valores.
? TIME()  && Hora actual del sistema 
SECONDS() retorna el número de segundos pasados desde la medianoche. Se puede utilizar para medir intervalos cortos de tiempo en un proceso. Recordar que este valor vuelve a 0 (cero) a partir de la medianoche.
nSegundos = SECONDS()
FOR nI = 1 TO 3
  INKEY(1)
ENDFOR
? SECONDS() - nSegundos, "segundos transcurridos" 
SYS(1) retorna una cadena de caracteres con el número de día Juliano de la fecha actual del sistema.
SYS(10,nDiaJuliano) retorna una cadena de caracteres con la fecha correspondiente al día Juliano pasado como parámetro.
SYS(11,dFecha) retorna una cadena de caracteres con el número de día Juliano de la fecha pasada como parámetro.
? SYS(1)
? SYS(10,VAL(SYS(1)))
? SYS(11,DATE(2005,1,1))
Los valores válidos en Visual FoxPro para los días días del calendario Juliano están comprendidos entre el 14 de Setiembre de 1752 y el 31 de Diciembre de 9999.

Funciones definidas por el usuario

A continuación describiremos diversas funciones definidas por el usuario (UDF) que utilizan las funciones nativas de Visual FoxPro descriptas al comienzo de este artículo, que nos permiten trabajar con expresiones Date y DateTime. Esta funciones están publicadas en PortalFox y algunas fueron ligeramente modificadaspara este este artículo.
Último día del mes: Esta función retorna la fecha del último día del mes de una expresión Date o DateTime pasada como parámetro.
? EoM(DATE())
FUNCTION EoM(tdFecha)
  LOCAL ld 
  ld = GOMONTH(tdFecha,1)
  RETURN ld - DAY(ld)
ENDFUNC 
Primer día del mes: Esta función retorna la fecha del primer día del mes de una expresión Date o DateTime pasada como parámetro.
? BoM(DATE())
FUNCTION BoM(tdFecha)
  RETURN DATE(YEAR(tdFecha),MONTH(tdFecha),1)
ENDFUNC 
Cantidad de días de un mes: Esta función retorna la cantidad de días que tiene el mes de una expresión Date o DateTime pasada como parámetro.
? DiasDelMes(DATE(2004,2,1))
FUNCTION DiasDelMes(tdFecha)
  LOCAL ld
  ld = GOMONTH(tdFecha,1)
  RETURN DAY(ld - DAY(ld))
ENDFUNC 
Edad de una persona: Calcula la edad de una persona pasando como parámetros la fecha de nacimiento y la fecha a la cual calculamos la edad. Si no se pasa el segundo parámetro se toma por defecto la fecha actual.
? Edad(DATE(2000,3,1))
FUNCTION Edad(tdNac, tdHoy)
  LOCAL lnAnios
  IF EMPTY(tdHoy)
    tdHoy = DATE()
  ENDIF
  lnAnios = YEAR(tdHoy) - YEAR(tdNac)
  IF GOMONTH(tdNac, 12 * lnAnios) > tdHoy
    lnAnios = lnAnios - 1
  ENDIF
  RETURN lnAnios
ENDFUNC 
Diferencia entre dos fechas en años, meses y días: Calcula la cantidad de años, meses y días entre dos expresiones de tipo Date pasadas como parámetros. (esta función utiliza la UDF DiasDelMes()).
? 

Diferencia_AMD(DATE(2000,3,1), DATE())
FUNCTION Diferencia_AMD(tdIni, tdFin)
  LOCAL ldAux, lnAnio, lnMes, lnDia, lcRet
  *--- Fecha inicial siempre menor
  IF tdIni > tdFin
    ldAux = tdIni
    tdIni = tdFin
    tdFin = ldAux
  ENDIF
  lnAnio = YEAR(tdFin) - YEAR(tdIni)
  ldAux = GOMONTH(tdIni, 12 * lnAnio)
  *--- No cumplio el año aun
  IF ldAux > tdFin
    lnAnio = lnAnio - 1
  ENDIF
  lnMes = MONTH(tdFin) - MONTH(tdIni)
  IF lnMes < 0
    lnMes = lnMes + 12
  ENDIF
  lnDia = DAY(tdFin) - DAY(tdIni)
  IF lnDia < 0
    lnDia = lnDia + DiasDelMes(tdIni)
  ENDIF
  *--- Si el dia es mayor, no cumplio el mes
  IF (DAY(tdFin) < DAY(tdIni))
    IF lnMes = 0
      lnMes = 11
    ELSE
      lnMes = lnMes - 1
    ENDIF
  ENDIF
  lcRet = ALLTRIM(STR(lnAnio))+ " años, " + ;
    ALLTRIM(STR(lnMes))+ " meses y " + ;
    ALLTRIM(STR(lnDia))+ " días"
  RETURN lcRet
ENDFUNC 
Diferencias entre dos variables DateTime: Calcula la cantidad de días, horas, minutos y segundos entre dos expresiones DateTime pasadas como parámetros.
? Diferencia_DHMS(DATETIME

(2000,3,1,12,10,05),DATETIME())
FUNCTION Diferencia_DHMS(ttIni,ttFin)
  LOCAL ln, lnDia, lnHor, lnMin, lnSeg
  IF EMPTY(ttFin)
    ttFin = DATETIME()
  ENDIF
  ln = ttFin - ttIni
  lnSeg = MOD(ln,60)
  ln = INT(ln/60)
  lnMin = MOD(ln,60)
  ln = INT(ln/60)
  lnHor = MOD(ln,24)
  lnDia = INT(ln/24)
  RETURN ALLTRIM(STR(lnDia))+ " días, "+ ;
    TRANSFORM(lnHor, "@L 99")+ " horas, "+ ;
    TRANSFORM(lnMin, "@L 99")+ " minutos, "+ ;
    TRANSFORM(lnSeg, "@L 99")+ " segundos"
ENDFUNC 
Segundos a hora: Transforma una cantidad de segundos pasados como parámetro al formato hora "HH:MM:SS". Con esta función podemos transformar la cantidad de segundos devueltos de una diferencia de dos expresiones DateTime.
lnSeg = DATETIME() - DATETIME(2004,3,1,12,10,05)
? Seg2Hor(lnSeg)
FUNCTION Seg2Hor(tnSegundos)
  LOCAL lnHoras, lnMinutos, lnSegundos
  lnHoras = INT(tnSegundos/3600)
  lnMinutos = INT(((tnSegundos-(lnHoras*3600))/60))
  lnSegundos = MOD(tnSegundos,60)
  RETURN IIF(lnHoras < 100,TRANSFORM(lnHoras,"@L 99"),ALLTRIM(STR(lnHoras))) + ;
    ":" + TRANSFORM(lnMinutos,"@L 99") + ;
    ":" + TRANSFORM(lnSegundos,"@L 99")
ENDFUNC 
Validar una fecha: Retorna verdadero si la fecha (año,mes,día) pasada como parámetro es válida.
? EsFechaValida(2004,2,30)
FUNCTION EsFechaValida(tnAnio, tnMes, tnDia)
  RETURN ;
    VARTYPE(tnAnio) = "N" AND ;
    VARTYPE(tnMes) = "N" AND ;
    VARTYPE(tnDia) = "N" AND ;
    BETWEEN(tnAnio, 100, 9999) AND ;
    BETWEEN(tnMes, 1, 12) AND ;
    BETWEEN(tnDia, 1, 31) AND ;
    NOT EMPTY(DATE(tnAnio, tnMes, tnDia))
ENDFUNC
Saber si un año es bisiesto: Retorna verdadero si el año pasado como parámetro es bisiesto.
? EsBisiesto(2004)
FUNCTION EsBisiesto(tnAnio)
  RETURN NOT EMPTY(DATE(tnAnio,2,29))
ENDFUNC 
Calcular una fecha festiva: Retorna una fecha festiva como por ejemplo el "Día de la Madre" que en algunos países se celebra el "Tercer Domingo de Octubre". Los parámetros que recibe la esta función son los siguientes:
tnOrdinal: El ordinal que se desea saber (1°, 2°, 3°, ...) tnDiaSem: El día de la semana (1=Dom, 2=Lun, ..., 7=Sáb) tnMes: El número del mes (1=Ene, 2=Feb, ..., 12=Dic) tnAnio: El año
*-- Tercer Domingo de Octubre de 2004
? FechaFestiva(3,7,10,2004)
FUNCTION FechaFestiva(tnOrdinal,tnDiaSem,tnMes,tnAnio)
  RETURN DATE(tnAnio,tnMes,1) + tnOrdinal * 7 - ;
    DOW(DATE(tnAnio,tnMes,1) + tnOrdinal * 7 -1,tnDiaSem)
ENDFUNC 
Fecha en español: Retorna una cadena con la fecha en español en formato "Sábado 01 de Enero de 2005"
? cFecha(DATE(2005,1,1))
FUNCTION cFecha(tdFecha)
  LOCAL aDias(7), aMeses(12)
  aDias[1]="Domingo "
  aDias[2]="Lunes "
  aDias[3]="Martes "
  aDias[4]="Miércoles "
  aDias[5]="Jueves "
  aDias[6]="Viernes "
  aDias[7]="Sábado "
  aMeses[1]="Enero"
  aMeses[2]="Febrero"
  aMeses[3]="Marzo"
  aMeses[4]="Abril"
  aMeses[5]="Mayo"
  aMeses[6]="Junio"
  aMeses[7]="Julio"
  aMeses[8]="Agosto"
  aMeses[9]="Setiembre"
  aMeses[10]="Octubre"
  aMeses[11]="Noviembre"
  aMeses[12]="Diciembre"
  RETURN aDias(DOW(tdFecha,1)) + ;
    TRANSFORM(DAY(tdFecha),"@L 99") + ;
    " de " + aMeses(MONTH(tdFecha)) + ;
    " de " + TRANSFORM(YEAR(tdFecha),"@L 9999")
ENDFUNC 

Configuraciones

Se debe recordar que muchas de las funciones de fecha y hora están afectadas por las configuraciones de Windows y Visual FoxPro.Se recomienda la lectura en la ayuda de la sintaxis y alcance de los siguientes comandos: SET DATE, SET CENTURY, SET HOURS, SET SECONDS, SET SYSFORMAT, SET FDOW, SET FWEEK, SET STRICTDATE y SET MARK.

Final

Estas son la mayoría de las funciones de Visual FoxPro referidas a expresiones de fechas y horas. En este Blog se pueden encontrar mas funciones definidas por el usuario referidas a fechas y horas.

26 comentarios :

  1. Me sirvió mucho; muchas gracias.
    Javier Romero Fiallos
    Guayaquil-Ecuador

    ResponderBorrar
  2. Muy buen contenido, me fue de gran ayuda...
    Luis Ramírez, El Salvador..

    ResponderBorrar
  3. Excelente publicación.
    Saludos,

    Jeisson Zuluaga
    Ibagué - COLOMBIA

    ResponderBorrar
  4. Muy buenas esas funciones. Las había olvidado.

    ResponderBorrar
  5. Aunque ha pasado màs de una dècada de esta publicaciòn, el contenido de la misma sigue siendo de gran interès.

    ResponderBorrar
  6. Muchas gracias. Me ayudó muchisimo este contenido
    Jorge Galicia

    ResponderBorrar
  7. Buenisimo, gracias por el dato del date()
    Me ha servido mucho
    Oscar

    ResponderBorrar
  8. como se ejecuta por ejem tengo una dbf con los campos fecha de inicio (pd_naci), la fecha fin (pd_cfec) y el campo edad donde supuestamente debe salir el resultado... soy recontra nuevo en este tema esa es mi duda...Diferencia entre dos fechas en años, meses y días

    ResponderBorrar
  9. Curiosamente una fecha l función ctod() no me la esta aceptando ... 01/04/2001. Porque será? Me devuelve { / / }. Sabrán porque?

    ResponderBorrar
    Respuestas
    1. Revisa la configuración de la fecha. Para que te funciones debes setear SET DATE TO DMY (day month year) si por algún motivo tienes seteado como SET DATE TO YMD te devolverá fecha vacía " / / "

      Borrar
    2. ejecuta en la ventana de comandos SET DATE TO DMY. Probablemente está configurado com YMD year month day que es lo que usan en EEUU

      Borrar
  10. Curiosamente una fecha con la función ctod() no me la esta aceptando ... 01/04/2001. Porque será? Me devuelve { / / }. Sabrán porque?

    ResponderBorrar
  11. me gusta mucho VFP , una lastima que lo dejaran morir, lo aprendí en el 82 y sigue vigente en mi mente, de hecho ejecuto la versión 5 de Fox

    ResponderBorrar
  12. Excelente información conocí en el 84 a DbaseII, me a gustado desde siempre
    actualmente manejo VFP5 y le saco provecho, quisiera migrar a opensource, pero me sale openXava

    ResponderBorrar
  13. Buenos dias.
    Os agradeceria me ayudarais con un aasunto de hora.
    Voy a desarrollar un sistema de control de llegadas y salidas del pèrsonal laboral y me gustaria saber si existe alguna funcion para conocer la fecha y hora real y no la que tiene el sistema, ya que esta la podrian cambiar los usuarios antes de registrar la entrada/salida.
    Gracias.
    Manuel de Sevilla

    ResponderBorrar
  14. Llevo usando Fox desde 1994, me encanta y aunque por necesidades laborales tengo que usar lenguajes nuevos, a la menor oportunidad regreso al zorrito para todo lo que no me sea solicitado en un lenguaje específico.

    ResponderBorrar
  15. Excelente articulo, aun lo consulto cuando tengo alguna duda.

    ResponderBorrar

Los comentarios son moderados, por lo que pueden demorar varias horas para su publicación.