;;; Las siguientes funciones son las utilizadas dentro de la gram tica de ;;; fechas para las transformaciones necesarias de la fecha , el tratamiento ;;; de las fechas ambiguas y dem s. (in-package 'dypar) (defvar *fecha-loaded* t) ;;; las siguientes funciones nos devuelven una lista formada por tres numeros, ;;; en el caso de que sea una fecha fija : (dia1 mes1 a¤o1), o por seis ;;; numeros en el caso de que sea un periodo de tiempo : (dia1 mes1 a¥o1 ;;; dia2 mes2 a¥o2) ;; Devuelve una fecha fija (defun time1 (dia mes a¤o) (list dia mes a¤o)) ;; Devuelve un mes completo o un a¤o completo ;; "en el mes de enero" "en el a¤o 86" ;; Time2 nos devuelve la fecha final (defun time2 (mes a¤o) (if (eql mes 'todos ) (append (list 1 1 a¤o) (if (eql a¤o (a¤o-actual)) (fecha-actual) (list 30 12 a¤o))) (list 1 mes (if (> mes (mes-actual)) (setf a¤o (- a¤o 1)) a¤o) (if (eql mes (mes-actual)) (dia-actual) 30) mes a¤o ))) ;; Calcula un per¡odo de tiempo. "tiempo" nos dice si el usuario habla de ;; dias, meses, a¤os.... ;; "cifra2" indica la "clase" de dias (semana,quincena..) o meses ;; (semestre,trimestre.....) ;; y "cifra1" es el n£mero de dias,quincenas,estc. ;; Se aplica a frases como "los tres ultimos semestres" o "los anteriores ;; diez dias" (defun time4 (cifra1 cifra2 tiempo) (let* ((dia2 (if (or (eql 7 cifra2) (eql 15 cifra2)) (domingo-anterior) (dia-actual))) (mes2 (mes-actual)) (a¤o2 (a¤o-actual)) (dia1 dia2) (mes1 mes2) (a¤o1 a¤o2)) (case tiempo (a¤o (setf mes1 1 mes2 12) (setf dia1 1 dia2 30) (setf a¤o1 (- a¤o2 (* cifra1 cifra2)) a¤o2 (- a¤o2 1))) (dia (setf dia1 (- dia2 (* cifra1 cifra2)))) (mes (setf dia1 1 dia2 30) (case cifra2 (1 (setf mes2 (- mes2 1))) (3 (cond ((and(< 0 mes2) (> 4 mes2)) (setf mes2 0)) ((and(< 3 mes2) (> 7 mes2)) (setf mes2 3)) ((and(< 6 mes2) (> 10 mes2)) (setf mes2 6)) ((and(< 9 mes2) (> 13 mes2)) (setf mes2 9)))) (4 (cond ((and(< 0 mes2) (> 5 mes2)) (setf mes2 0)) ((and(< 4 mes2) (> 9 mes2)) (setf mes2 4)) ((and(< 8 mes2) (> 13 mes2)) (setf mes2 8)))) (6 (cond ((and(< 0 mes2) (> 7 mes2)) (setf mes2 0)) ((and(< 6 mes2) (> 13 mes2)) (setf mes2 6))))) (setf mes1 (+ 1 (- mes2 (* cifra1 cifra2)))))) (if (<= dia1 0) (do (( dia dia1 (+ 30 dia)) ( mes mes1 (- mes 1))) ((> dia 0) (setf dia1 dia mes1 mes)))) (if (<= mes1 0) (do (( mes mes1 (+ 12 mes)) ( a¤o a¤o1 (- a¤o 1))) ((> mes 0) (setf mes1 mes a¤o1 a¤o)))) (if (<= mes2 0) (do (( mes mes2 (+ 12 mes)) ( a¤o a¤o2 (- a¤o 1))) ((> mes 0) (setf mes2 mes a¤o2 a¤o)))) (list dia1 mes1 a¤o1 dia2 mes2 a¤o2))) (defun time6 (cifra1 cifra2 a¤o) (let* ((mes2 (mes-actual)) (mes1 mes2)) (case cifra2 (3 (cond ((equal cifra1 'primero) (setf mes1 1 mes2 3)) ((equal cifra1 'segundo) (setf mes1 4 mes2 6)) ((equal cifra1 'tercero) (setf mes1 7 mes2 9)) ((equal cifra1 'ultimo) (setf mes1 10 mes2 12)))) (4 (cond ((equal cifra1 'primero) (setf mes1 1 mes2 4)) ((equal cifra1 'segundo) (setf mes1 5 mes2 8)) ((or (equal cifra1 'ultimo) (equal cifra1 'tercero)) (setf mes1 9 mes2 12)))) (6 (cond ((equal cifra1 'primero) (setf mes1 1 mes2 6)) ((or (equal cifra1 'ultimo) (equal cifra1 'segundo)) (setf mes1 7 mes2 12))))) (list 1 mes1 a¤o 30 mes2 a¤o))) ;; calcula periodos de tiempo definidos por "desde hace 13 dias" y similar ;; ;; Si inicio es 1 devuelve la fecha inicial ;; Si inicio es 2 devuelve la fecha final ;; (defun time0 (cifra1 cifra2 tiempo) (let* ((dia2 (dia-actual)) (mes2 (mes-actual)) (a¤o2 (a¤o-actual)) (dia1 dia2) (mes1 mes2) (a¤o1 a¤o2)) (case tiempo (dia (setf dia1 (- dia2 (* cifra1 cifra2)))) (mes (setf mes1 (- mes2 (* cifra1 cifra2)))) (a¤o (setf a¤o1 (- a¤o2 (* cifra1 cifra2))))) (if (<= dia1 0) (do (( dia dia1 (+ 30 dia)) ( mes mes1 (- mes 1))) ((> dia 0) (setf dia1 dia mes1 mes)))) (if (<= mes1 0) (do (( mes mes1 (+ 12 mes)) ( a¤o a¤o1 (- a¤o1 1))) ((> mes 0) (setf mes1 mes a¤o1 a¤o)))) (list dia1 mes1 a¤o1))) ;; "desde enero a junio del 87" etc ;; (defun time3 (fecha1 fecha2) (let ((dia1 (car fecha1)) (mes1 (second fecha1)) (a¤o1 (third fecha1)) (dia2 (car fecha2)) (mes2 (second fecha2)) (a¤o2 (third fecha2))) (cond ((and (< mes2 mes1) (equal a¤o1 a¤o2)) (setf a¤o1 (- a¤o1 1))) ((and (< (mes-actual) mes2) (eql a¤o2 (a¤o-actual)) (eql a¤o1 a¤o2)) (setf a¤o1 (- a¤o1 1) a¤o2 (- a¤o2 1)))) (list dia1 mes1 (if (< a¤o2 a¤o1) a¤o2 a¤o1) dia2 mes2 a¤o2))) ;; fecha actual ;; (defun fecha-actual () (multiple-value-bind (s d f dia mes a¤o) (get-decoded-time) (list dia mes a¤o))) ;; dia actual (defun dia-actual () (multiple-value-bind (s d f dia) (get-decoded-time) dia)) ;; mes actual (defun mes-actual () (multiple-value-bind (s d f dia mes) (get-decoded-time) mes)) ;; mes pasado (defun mes-pasado () (multiple-value-bind (s d f dia mes) (get-decoded-time) (- mes 1))) ;; a¤o actual (defun a¤o-actual () (multiple-value-bind (s d f dia mes a¤o) (get-decoded-time) a¤o)) ;; a¤o pasado (defun a¤o-pasado () (multiple-value-bind (s d f dia mes a¤o) (get-decoded-time) (- a¤o 1))) ;; fecha-inicial (defun fecha-inicial () (list 1 1 (a¤o-actual))) ;; domingo anterior (defun domingo-anterior() (multiple-value-bind (s d f dia mes a¤o do-anterior) (get-decoded-time) (- dia (+ 1 do-anterior)))) ;;lee n£meros entre 1 y 31 (def-op $leer-dia $n () (inp) (and (numberp (car inp)) (< (car inp) 32) (> (car inp) 0))) ;; lee n£meros entre 1 y 12 (def-op $leer-mes $n () (inp) (and (numberp (car inp)) (< (car inp) 13) (> (car inp) 0))) ;; lee n£meros entre 1980 y el a¤o actual (def-op $leer-a¤o $n () (inp) (or (and (numberp (car inp)) (<= (car inp) (a¤o-actual)) (>= (car inp) 1980)) (and (numberp (car inp)) (<= (car inp) 99) (>= (car inp) 80)))) ;; "esta semana" "este mes"...... (defun time5 (tiempo) (let ((dia1) (dia2) (mes1) (mes2) (a¤o1) (a¤o1)) (case tiempo (trimestre (setf dia1 1 mes1 (cond ((< (mes-actual) 4) 1) ((< (mes-actual) 7) 3) ((< (mes-actual) 10) 6) ((< (mes-actual) 13) 9)) a¤o1 (a¤o-actual))) (mes (setf dia1 1 mes1 (mes-actual) a¤o1 (a¤o-actual))) (a¤o (setf dia1 1 mes1 1 a¤o1 (a¤o-actual))) (semana (setf dia1 (+ 1 (domingo-anterior)) mes1 (mes-actual) a¤o1 (a¤o-actual)))) (append (list dia1 mes1 a¤o1) (fecha-actual)))) ;;; La siguiente funcion convierte la fecha que nos ha devuelto la gramatica ;;; de fechas en el formato en el que la base de datos la contiene (defun fec-string (date) (let ((dia nil) (mes nil) (a¥o nil)) (setf dia (princ-to-string (car date))) (setf mes (princ-to-string (second date))) (setf a¥o (princ-to-string (third date))) (if (equal (length dia) 1) (setf dia (string-append "0" dia))) (if (equal (length mes) 1) (setf mes (string-append "0" mes))) (if (equal (length a¥o) 2) (setf a¥o (string-append "19" a¥o))) (string-append a¥o mes dia ))) ;;; la siguiente funcion, haciendo uso de la anterior, deja preparada para ;;; la select la condicion que describe la fecha ; es decir, si tenemos dos ;;; fechas eso quiere decir que la condicion es que entre ambas se encuentre ;;; dicho campo de la base, si tenemos solo una puede ser que exijamos fecha ;;; posterior o anterior a esa, etc. (defun fecha (!fecha1 !fecha2 !fecha !fecha-ini !fecha-fin) (let ((fecha1 !fecha1) (fecha2 !fecha2) (fecha !fecha) (fecha-ini !fecha-ini) (fecha-fin !fecha-fin) (fecha-string)) (if fecha1 (setf fecha-string (if (equal fecha1 fecha2) (string-append " slc_pefecsol = " (fec-string fecha1)) (string-append " slc_pefecsol between " (fec-string fecha1) " and " (fec-string fecha2))))) (if (and fecha (not (stringp fecha)) (not (equal fecha 'trimestre)) (not (equal fecha 'ultimamente))) (setf fecha-string (string-append " slc_pefecsol between " (fec-string (list (car fecha) (second fecha) (third fecha))) " and " (fec-string (nthcdr 3 fecha))))) (if (and fecha (stringp fecha)) (setf fecha-string fecha)) (if (or (equal fecha 'trimestre) (equal fecha 'ultimamente)) (setf fecha-string fecha)) (if fecha-ini (setf fecha-string (string-append " slc_pefecsol between " (fec-string (list (car fecha-ini) (second fecha-ini) (third fecha-ini))) " and " (fec-string (nthcdr 3 fecha-fin))))) fecha-string)) ;; defino una estructura que tiene como atributos ;; usuario frase usuario ;; frase frase del menu de posibles interpretaciones ;; interpretacion interpretacion de la frase ;; la lista lista-interpretaciones contiene todas las estructuras creadas (defstruct interpretaciones usuario frase interpretacion) (setf lista_interpretaciones (list (make-interpretaciones :usuario (quote trimestre) :frase "Los ultimos noventa dias" :interpretacion (time4 90 1 'dia)) (make-interpretaciones :usuario (quote trimestre) :frase "Los dias que llevamos de este trimestre natural." :interpretacion (time5 'trimestre)) (make-interpretaciones :usuario (quote ultimamente) :frase "Los ultimos diez dias." :interpretacion (time4 10 1 'dia)) (make-interpretaciones :usuario (quote ultimamente) :frase "De un mes a esta parte." :interpretacion (time4 30 1 'dia)) (make-interpretaciones :usuario (quote ultimamente) :frase "Los ultimos tres dias." :interpretacion (time4 3 1 'dia)))) ;; obtenemos la interpretacion de la frase elegida (defun elige (frase) (dolist (var lista_interpretaciones salida) (if (equal frase (interpretaciones-frase var)) (setf salida (interpretaciones-interpretacion var))))) ;; esta funcion hace que aparezca en pantalla el menu correspondiente ;; a las posibles interpretaciones de una entrada ambigua (cadena) (defun resolver-ambiguedad (cadena) (let ((frase cadena) (lista lista_interpretaciones) (nueva-cadena nil) (i 1) (opcion)) (dolist (var lista nueva-cadena) (cond ((equal frase (interpretaciones-usuario var)) (setf nueva-cadena (append nueva-cadena (list (interpretaciones-frase var))))))) (escribe-mensaje (format *query-io* "~2& Delimite el periodo con mas exactitud.~ Teclee el numero de la opcion elegida.~2%") (dolist (var nueva-cadena lista) (format *query-io* "~& ~a-. ~@(~a~) " i var ) (setf lista (append lista (list i var))) (setf i (+ 1 i))) (format *query-io* "~2& Opci¢n: ") (setq opcion (do ((leido (read *query-io*) (read *query-io*))) ((and (numberp leido) (> leido 0) (< leido i)) leido) (format *query-io* "~& Opci¢n(1..~d): " (- i 1))))) (setf nuevo (car (cdr (member opcion lista)))) (elige nuevo))) ;;;;;;;;;;;;;;;;;;;;;;;;;; FIN ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;