Lo que fue el año 2.000
IDENTIFICATION DIVISION. (Introduccion)

¿ Porque es un problema la llegada del año 2.000 ?. Cuando desde Cobol le pedimos al Sistema que nos de la fecha actual, ésta nos viene en formato AAMMDD y los dígitos correspondientes al milenio los deprecia, con lo cual cuando intentamos comparar fechas de distinto siglo el resultado puede ser erróneo, por ejemplo:

Que fecha sería mayor 19991020 (20 de Octubre de 1.999) o 20000115 (15 de Enero del 2.000), en teoría es mayor la que hace referencia a un año mayor, pero al depreciar los 2 primer dígitos y solo ofrecernos 991020, para la primera y 000115 para la segunda resulta que la fecha que hace referencia a 1999 la considera mayor.

Vamos a ver todo ésto lo mas claramente posible (quizás para la mayoría todo ésto sea muy evidente, pero intento que para las personas que no lo sea, lo entiendan bien), para comprobar cuando una fecha es mayor que otra, se comparan como si de un número entero se tratase, 991020 es mayor que 000115 (novecientos noventa y un mil veinte es mayor que ciento quince).Pero si tuviéramos la fecha en formato completo AAAAMMDD, el resultado sería distinto, porque 20000115 es mayor que 19991020(veinte millones ciento quince es mayor que diecinueve millones novecientos noventa y un mil veinte).

Formato AAMMDD
991.020
000.115

Formato AAAAMMDD
20.000.115
19.991.020


¿ Porque se guardan las fechas en formato AAMMDD y no como se leen en español DDMMAA ?. Creo que con la respuesta anterior está todo dicho, si el formato fuera el español no podriamos operar como si fuesen números, ya que 210598 sería mayor que 190598, pero en cambio sería menor que 010698, y la realidad nos dice que eso no es así, la fecha mayor sería 010698, luego 210598 y por último 190598.

Para verlo todo un poco mas claro mirad a la tabla siguiente, están ordenados de mayor a menor, fijaros que hay diferencia entre los dos formatos, mientras para el DDMMAA la fecha 21 de Mayo de 1.998 sería la mayor, para el formato AAMMDD la mayor es el 1 de Junio de 1.998, por tanto la correcta. (el hecho de poner el separador de miles es para que podais apreciar mejor la cifra mayor, imaginándola como un número entero).

Formato DDMMAA
210.598
190.598
010.698

Formato AAMMDD
980.601
980.521
980.519



ENVIRONMENT DIVISION. (Desarrollo)

El análisis, es sin duda la parte mas importante de todo el proyecto, hay que tener bien inventariado tanto los archivos a los que va a afectar, como a los programas que utilizan esos archivos.

Obviamente la manera que tenemos cada programador para hacer nuestro trabajo es muy diferente, por lo que entiendo que no todos tendremos los mismos criterios ni la misma forma de enfocar nuestras aplicaciones o proyectos. A continuación os detallo mis criterios:
  • Trabajo en UNIX SVR4 con RM/COBOL 85 Versión 6.00.00, sin ninguna herramienta adicional.
  • Todas las FD´s de los ficheros las tengo en archivos aparte que luego llamo con copy desde cada programa para evitarme errores con los nombre de los campos.
  • Los programas van en un directorio y los archivos en otro.
  • La Working-Storage Section es común para todos los programas, igual nombre para las variables.
  • En la Select nunca doy el lugar absoluto del archivo para tener mas libertad, es decir si el archivo Clientes.dat se encuentra en el directorio /home/datos y los programas están en /home/programas, la dirección a la que hago referencia sería "../datos/clientes.dat" , de ésta manera si ahora en vez de estar todo colgado de /home lo estuviera de /pepe , no habría ningún problema.
Bien, una vez hechas las consideraciones oportunas pasamos al detalle del proyecto.
Es muy importante tener todo sobre papel, es decir un listado con todos los programas y lo que hacen para no perderte, otro con todos los archivos y una carpeta con todas las FD´s listadas (se que es un trabajo meticuloso, pero a la larga los resultados se obtienen y los errores serán mínimos).

A continuación haremos una copia de nuestros directorios de programas y archivos en otro lugar, en mi caso los originales parten de /home , teniendo los programas en un directorio y los archivos en otro, pues bien esa misma estructura se copia a /home1 o a cualquier otro directorio, para ir haciendo los cambios sin entorpecer la labor de la empresa.

Yo he preferido que tanto en pantalla como en los listados, la fecha siga apareciendo en 6 dígitos, por varios motivos:
  • El usuario no tendrá que modificar su hábito de introducir fechas, sería mucho mas latoso para él introducir 8 dígitos que 6, además de su falta de costumbre y consiguiente probabilidad de error. Él no debe de notar nada, menos problemas.
  • En las cabeceras de los listados no hay que hacer ninguna modificación.
  • En el diseño de la pantalla no hay que modificar, en alguna hasta sería un grave problema, puesto que están llenas y no cabe ni una coma.
  • Y por último. hay que pensar que en el 2.001 ya todo volverá a la normalidad (practicamente) porque volveremos a comparar fechas del mismo siglo.
La solución que yo he tomado vale unicamente hasta el año 2.090 pero por desgracia para ese año....., de todas formas solo cambiano un número de una de las rutinas problema resuelto. DATA DIVISION. (Variables)

Para todo el proceso he creado 5 rutinas pequeñas que serán llamadas tantas veces como sea necesario desde los programas.

Puesto que van a ir en todos los programas os aconsejo que las pongais en un archivo y luego copy en todos los programas, si ya tenis algún archivo pequeño que realice alguna tarea común y sea llamado desde los programas, pues lo implementais en éste y os evitais poner otra copy .

Las variables necesarias para aplicar las rutinas son las siguientes:

WORKING-STORAGE SECTION.
........
........
01  FECA      PIC 9(6). (fecha 6 dígitos en castellano DDMMAA).
01  FECO      REDEFINES FECA.
     02  FDIA  PIC 99. (dia)
     02  FMES PIC 99. (mes)
     02  FANO PIC 99. (año)

01  FESPA      PIC 9(8). (fecha 8 dígitos en castellano DDMMAAAA).
01  FEXPA      REDEFINES FESPA.
     02  FPDIA  PIC 99. (dia)
     02  FPMES PIC 99. (mes)
     02  FPSIG  PIC 99. (siglo)
     02  FPANO PIC 99. (año)

01  FEREV      PIC 9(8). (fecha 8 dígitos en inglés SSAAMMDD).
01  FEREX      REDEFINES FEREV.
     02  FRSIG  PIC 99. (dia)
     02  FRANO PIC 99. (mes)
     02  FRMES PIC 99. (siglo)
     02  FRDIA  PIC 99. (año).

Si no utilizais una Working común para todos vuestros programas, es conveniente introducir las variables en un archivo y que sea llamado desde los programas dentro de la Working. Por supuesto los nombre de las variables podeis cambiarlos, teniendo en cuenta cambiar también las rutinas.



PROCEDURE DIVISION. (Rutinas)

A continuación os detallo las rutinas y una explicación de lo que hacen:

PROCEDURE DIVISION.
........
........
A2000.
    IF FANO < 90 MOVE 20 TO FPSIG FRSIG
        ELSE MOVE 19 TO FPSIG FRSIG.
    MOVE FDIA TO FPDIA FRDIA.
    MOVE FMES TO FPMES FRMES.
    MOVE FANO TO FPANO FRANO.
Esta rutina se encarga de adaptarnos una fecha de 6 dígitos con formato DDMMAA a dos variables de 8 dígitos, FESPA en formato DDMMAASS y FEREV con formato SSAAMMDD. (Comunmente llamo FESPA a un formato en castellano y a FEREV a uno en inglés.

Observamos que la fecha que le damos siempres va en formato castellano DDMMAA.
C2000.
    MOVE FPDIA TO FRDIA.
    MOVE FPMES TO FRMES.
    MOVE FPANO TO FRANO.
    MOVE FPSIG TO FRSIG.
Partiendo de un formato de 8 dígitos en castellano y en la variable FESPA, nos devuelve la variable FEREV con el formato inglés SSAAMMDD.
C2000R.
    MOVE FRDIA TO FPDIA.
    MOVE FRMES TO FPMES.
    MOVE FRANO TO FPANO.
    MOVE FRSIG TO FPSIG.
Partiendo de un formato de 8 dígitos en inglés y en la variable FEREV, nos devuelve la variable FESPA con el formato castellano DDMMSSAA.
DE8A6.
    MOVE FPDIA TO FDIA.
    MOVE FPMES TO FMES.
    MOVE FPANO TO FANO.
Partiendo de un formato de 8 dígitos en castellano y en la variable FESPA, nos devuelve la variable FECA con el formato DDMMAA con 6 dígitos.
DE8A6R.
    MOVE FRDIA TO FDIA.
    MOVE FRMES TO FMES.
    MOVE FRANO TO FANO.
Partiendo de un formato de 8 dígitos en inglés y en la variable FEREV, nos devuelve la variable FECA con el formato DDMMAA con 6 dígitos.

Ya veis que las rutinas son muy simples, pero si os acostumbrais, funcionan de maravilla.

El motivo de utilizar los dos formatos de fechas, es porque cuando el campo fecha de algún fichero solo es informativo y no voy a operar con el lo pongo en formato castellano DDMMSSAA, quizás no sea una buena opción pero como ya lo tenía así, no lo he cambiado. Si utilizais siempre la fecha en formato inglés SSAAMMDD, os sobrarán algunas rutinas.


ANALISIS.

Llegados a éste punto, solo queda explicar los pasos y poner un sencillo ejemplo. Principalmente se puede decir que tenemos dos pasos, la conversión de los archivos y la de los programas.

1. Conversión de archivos. Para cada archivo generamos un pequeño programa que lea el archivo y lo genere en otro con el campo fecha de 8 dígitos y el formato que hayamos elegido DDMMSSAA o SSAAMMDD.
Movemos todos los campos de un fichero a otro y al campo fecha le aplicamos la primera rutina la llamada A2000 , grabamos el nuevo registro y una vez concluido cambiamos los nombres de los archivos.

IDENTIFICATION DIVISION.
PROGRAM-ID. CAMBIO.
ENVIRONMENT DIVISION.
INPUT-OUTPUT SECTION.
FILE-CONTROL.

SELECT ARCHIVOANTIGUO ASSIGN TO RANDOM "ANTIGUO.DAT" ORGANIZATION INDEXED ACCESS DYNAMIC RECORD KEY KEYANTIGUO.
SELECT ARCHIVONUEVO ASSIGN TO RANDOM "NUEVO.DAT" ORGANIZATION INDEXED ACCESS DYNAMIC RECORD KEY KEYNUEVO.

DATA DIVISION.
FILE SECTION.
FD  ARCHIVOANTIGUO BLOCK 8 RECORDS RECORD 64 CHARACTERS
      LABEL RECORD STANDARD.
01  REGANTIGUO.
     02 KEYANTIGUO.
          03 ANTFECHA PIC 9(6). (formato inglés AAMMDD)
          03 ANTPRODUCTO PIC 9(4).
     02 ANTKILOS PIC 9(8).
     02 ANTPRECIO PIC 9(6).
     02 FILLER PIC X(40).

FD  ARCHIVONUEVO BLOCK 8 RECORDS RECORD 64 CHARACTERS
      LABEL RECORD STANDARD.
01  REGNUEVO.
     02 KEYNUEVO.
          03 NUEFECHA PIC 9(8). (formato inglés SSAAMMDD).
          03 NUEPRODUCTO PIC 9(4).
     02 NUEKILOS PIC 9(8).
     02 NUEPRECIO PIC 9(6).
     02 FILLER PIC X(38).

WORKING-STORAGE SECTION.
COPY "variables_para_las_rutinas".
PROCEDURE DIVISION.
INICIO.
     OPEN OUTPUT ARCHIVONUEVO CLOSE ARCHIVONUEVO.
     OPEN INPUT ARCHIVOANTIGUO I-O ARCHIVONUEVO.
UNO.
     READ ARCHIVOANTIGUO NEXT RECORD AT END GO FIN.
     MOVE ANTPRODUCTO TO NUEPRODUCTO.
     MOVE ANTKILOS TO NUEKILOS.
     MOVE ANTPRECIO TO NUEPRECIO.
     MOVE ANTFECHA TO FECA MOVE FDIA TO VARIABLE_PIC 99.
     MOVE FANO TO FDIA MOVE VARIABLE_PIC 99 TO FANO.      PERFORM A2000 MOVE FEREV TO NUEFECHA.
     WRITE REGNUEVO INVALID KEY DISPLAY "CAMBIO MAL".
     GO UNO.
FIN.
     CLOSE ARCHIVONUEVO ARCHIVOANTIGUO.
     STOP RUN.
COPY "rutinas".


Como veis es muy simple, he tenido que cambiar el orden del campo NUEFECHA , porque la rutina espera el campo fecha de 6 dígitos en formato DDMMAA.

Una vez terminado el proceso cambiamos el nombre a NUEVO.DAT por ANTIGUO.DAT y también la FD correspondiente para que el campo fecha tenga 8 dígitos.

Al comienzo os dije que todo esto se hiciera en un directorio aparte para poder probarlo bien antes de ponerlo definitivamente, por lo que ésta conversión no será valida hasta que la hagamos sobre los datos reales.

2. Conversión de programas. Una vez concluida la conversión de los archivos, nos disponemos a la de los programas, ésta será mas compleja cuanto mas utilicemos los campos de fecha. Como queremos seguir manteniendo en pantalla la fecha a 6 dígitos, cada vez que se introduzca una y la hayamos validado la movemos a la variable FECA y le pasamos la rutina A2000 , con lo que obtendremos las dos variables FESPA y FEREV , en castellano y en inglés para moverlas donde queramos.

Asimismo, cuando queramos mostrar una fecha de un archivo guardada en 8 dígitos la movemos a las variables FESPA o FEREV dependiendo del formato y le pasamos la rutina DE8A6 o DE8A6R respectivamente, devolviendonos la fecha en 6 dígitos en la variable FECA, siempre en formato castellano DDMMAA dispuesta para ser mostrada. Cuando hayamos convertido todos los programas y verificados con los archivos, estaremos dispuestos para hacerlo con los datos reales y poner fin al problema del año 2.000.

Hemos llegado al final, solo queda recordaros que todo esto es lo que yo he hecho y os aseguro que me funciona, habrá mas soluciones y mejores seguro. Si teneis alguna duda os podeis poner en contacto conmigo.

En mi empresa tenemos unos 260 programas y 85 archivos en los que existen campos fecha y la conversión definitiva tardó 3 horas y media, en la que logicamente ningún usuario pudo trabajar, ya veis que fue poco tiempo comparado con los calentamientos de cabeza que nos vamos a quitar.

Como final os voy a poner algunos consejos muy importantes:
  • Todo debe de estar probado, reprobado y vuelto a probar antes de hacerlo definitivamente.
  • Introduce albaranes o facturas o lo que sea con fechas de 1999 y 2000 para comprobar que realmente funciona y que con las fechas se puede operar bien.
  • Vuelve a compilar todos los programas en los que estén incluidos los archivos con el problema de la fecha y no se utilice el campo fecha, ya que la FD ha cambiado y por lo tanto la posición interna de los campos.


Si habeis llegado hasta aquí, FELICIDADES y MUCHAS GRACIAS, eso es que os ha interesado y ese era el fin de ésta página.



Este artículo proviene de Cobol en español
http://www.escobol.com

La dirección de esta noticia es:
http://www.escobol.com/modules.php?name=Sections&op=viewarticle&artid=40