Para aquellos que habéis estado en más de un proyecto, seguro que os ha pasado que en cada sitio almacenan las fechas de una manera distinta. En este artículo vamos a ver las formas más comunes de almacenar fechas y como pasarlas de uno a otro formato.
Fecha DB2
Es aquella que tiene formato "DATE" en la correspondiente tabla.
Su definición sería: AAAA-MM-DD
Ejemplos
COBOL: 01 WX-FECHA-DB2 PIC X(10) VALUE '2011-01-01'.
PL/I : DCL WX_FECHA_DB2 CHAR(10) INIT ('2011-01-01');
Fecha Juliana
En tabla se tendría formato DECIMAL (7), pues se trata de un número de 7 dígitos. La información que almacena es el año de 4 dígitos, y el día del año entre 1 y 365. Su definición sería: AAAADDD
Ejemplos
COBOL: 01 WX-FECHA-JUL PIC 9(7) VALUE 2011001.
PL/I : DCL WX_FECHA_JUL PIC '(7)9' INIT (2011001);
Fecha gregoriana
En tabla tendría formato DECIMAL (8), pues se trata de un número de 8 dígitos. La información que se almacena es el año de 4 dígitos, el mes y el día del mes.
Su definición sería: AAAAMMDD
Ejemplos
COBOL: 01 WX-FECHA-GREG PIC 9(8) VALUE 20110101.
PL/I : DCL WX_FECHA_GREG PIC '(8)9' INIT (20110101);
Pero a la hora de mostrar una fecha por pantalla, no se usa ninguno de esos formatos, sino el más entendible por el usuario: el mítico DD-MM-AAAA (01-01-2011).
Ya sea con guiones o con barras, la transformación a este formato suele ser común en los programas online.
Vamos a ver como transformaríamos cada uno de los formatos anteriores al formato de pantalla.
De AAAA-MM-DD a DD-MM-AAAA
(...)
WORKING-STORAGE SECTION.
01 WX-FECHA-DB2.
05 WX-AAAA-DB2 PIC 9(4).
05 FILLER PIC X.
05 WX-MM-DB2 PIC 9(2).
05 FILLER PIC X.
05 WX-DD-DB2 PIC 9(2).
01 WX-FECHA-ONLINE.
05 WX-DD-ONLINE PIC 9(2).
05 FILLER PIC X VALUE '-'.
05 WX-MM-ONLINE PIC 9(2).
05 FILLER PIC X VALUE '-'.
05 WX-AAAA-ONLINE PIC 9(4).
PROCEDURE DIVISION.
MOVE '1999-31-12' TO WX-FECHA-DB2
MOVE WX-AAAA-DB2 TO WX-AAAA-ONLINE
MOVE WX-MM-DB2 TO WX-MM-ONLINE
MOVE WX-DD-DB2 TO WX-DD-ONLINE
DISPLAY 'FECHA ONLINE:' WX-FECHA-ONLINE
STOP RUN
.
Como veis este cambio no tiene mucha ciencia^^
De AAAAMMDD a DD-MM-AAAA
(...)
WORKING-STORAGE SECTION.
01 WX-FECHA-GREG.
05 WX-AAAA-8 PIC 9(4).
05 WX-MM-8 PIC 9(2).
05 WX-DD-8 PIC 9(2).
01 WX-FECHA-ONLINE.
05 WX-DD-ONLINE PIC 9(2).
05 FILLER PIC X VALUE '-'.
05 WX-MM-ONLINE PIC 9(2).
05 FILLER PIC X VALUE '-'.
05 WX-AAAA-ONLINE PIC 9(4).
PROCEDURE DIVISION.
MOVE 19991231 TO WX-FECHA-8
MOVE WX-AAAA-8 TO WX-AAAA-ONLINE
MOVE WX-MM-8 TO WX-MM-ONLINE
MOVE WX-DD-8 TO WX-DD-ONLINE
DISPLAY 'FECHA ONLINE:' WX-FECHA-ONLINE
STOP RUN
.
Veis que es prácticamente lo mismo que en el caso anterior.
También puede ser necesario transformar las fechas entre el formato juliano y el gregoriano:
De AAAAMMDD a AAAADDD
(...)
WORKING-STORAGE SECTION.
01 WX-FECHA-JUL.
05 WX-AAAA-JUL PIC 9(4).
05 WX-DDD-JUL PIC 9(3).
01 WX-FECHA-GREG.
05 WX-AAAA-8 PIC 9(4).
05 WX-MM-8 PIC 9(2).
05 WX-DD-8 PIC 9(2).
PROCEDURE DIVISION.
MOVE 20111231 TO WX-FECHA-GREG
MOVE WX-AAAA-8 TO WX-AAAAA-JUL
MOVE WX-DD-8 TO WX-DD-JUL
IF WX-MM-8 EQUAL 12
ADD 30 TO WX-DD-JUL
SUBSTRACT 1 FROM WX-MM-8
END-IF
IF WX-MM-8 EQUAL 11
ADD 31 TO WX-DD-JUL
SUBSTRACT 1 FROM WX-MM-8
END-IF
IF WX-MM-8 EQUAL 10
ADD 30 TO WX-DD-JUL
SUBSTRACT 1 FROM WX-MM-8
END-IF
IF WX-MM-8 EQUAL 9
ADD 31 TO WX-DD-JUL
SUBSTRACT 1 FROM WX-MM-8
END-IF
IF WX-MM-8 EQUAL 8
ADD 31 TO WX-DD-JUL
SUBSTRACT 1 FROM WX-MM-8
END-IF
IF WX-MM-8 EQUAL 7
ADD 30 TO WX-DD-JUL
SUBSTRACT 1 FROM WX-MM-8
END-IF
IF WX-MM-8 EQUAL 6
ADD 31 TO WX-DD-JUL
SUBSTRACT 1 FROM WX-MM-8
END-IF
IF WX-MM-8 EQUAL 5
ADD 30 TO WX-DD-JUL
SUBSTRACT 1 FROM WX-MM-8
END-IF
IF WX-MM-8 EQUAL 4
ADD 31 TO WX-DD-JUL
SUBSTRACT 1 FROM WX-MM-8
END-IF
IF WX-MM-8 EQUAL 3
ADD 28 TO WX-DD-JUL
SUBSTRACT 1 FROM WX-MM-8
END-IF
DIVIDE WX-AAAA-8 BY 4 GIVING WX-AAAA-8 REMAINDER WX-RESTO
IF WX-RESTO EQUAL ZEROES
ADD 1 TO WX-DDD-JUL
END-IF
IF WX-MM-8 EQUAL 2
ADD 31 TO WX-DD-JUL
END-IF
DISPLAY 'FECHA JULIANA (YYYYDDD):' WX-FECHA-JUL
STOP RUN
.
Aquí ya se complica un poco la cosa. Normalmente suelen existir rutinas generales para hacer este formateo. Por ejemplo, una rutina que recibe la fecha en formato AAAAMMDD por linkage y la devuelve en formato AAAADDD.
De AAAADDD a AAAAMMDD
(...)
WORKING-STORAGE SECTION.
01 TABLA-MM-DD.
05 MM-01 PIC 9(3) COMP-3 VALUE 0.
05 MM-02 PIC 9(3) COMP-3 VALUE 31.
05 MM-03 PIC 9(3) COMP-3 VALUE 59.
05 MM-04 PIC 9(3) COMP-3 VALUE 90.
05 MM-05 PIC 9(3) COMP-3 VALUE 120.
05 MM-06 PIC 9(3) COMP-3 VALUE 151.
05 MM-07 PIC 9(3) COMP-3 VALUE 181.
05 MM-08 PIC 9(3) COMP-3 VALUE 212.
05 MM-09 PIC 9(3) COMP-3 VALUE 243.
05 MM-10 PIC 9(3) COMP-3 VALUE 273.
05 MM-11 PIC 9(3) COMP-3 VALUE 304.
05 MM-12 PIC 9(3) COMP-3 VALUE 334.
01 TABLA-MM-DD-R REDEFINES TABLA-MM-DD.
05 MM-DIAS OCCURS 12 TIMES
PIC 9(3) COMP-3.
01 WX-ANO-BIS PIC S9(3) COMP-3.
88 ANO-BIS-SI VALUE 0.
01 WX-FIL9 PIC S9(3) COMP-3.
01 WX-FECHA-JUL.
05 WX-AAAA-JUL PIC 9(4).
05 WX-DDD-JUL PIC 9(3).
01 WX-FECHA-GREG.
05 WX-AAAA-8 PIC 9(4).
05 WX-MM-8 PIC 9(2).
05 WX-DD-8 PIC 9(2).
PROCEDURE DIVISION.
DISPLAY 'FECHA JULIANA: 2011059'
MOVE 2011059 TO WX-FECHA-JUL
MOVE WX-AAAA-JUL TO WX-AAAA-8
*--- COMPROBAR AÑO BISIESTO: RESTO = 0 = AÑO BISIESTO
DIVIDE WX-AAAA-JUL BY 4 GIVING WX-FIL9 REMAINDER WX-ANO-BIS
*--- CORREGIR VALORES MM-DD PARA AÑO BISIESTO
IF ANO-BIS-SI
ADD 1 TO MM-03
MM-04
MM-05
MM-06
MM-07
MM-08
MM-09
MM-10
MM-11
MM-12
END-IF
*--- DETERMINA EN QUE MES ESTAMOS
PERFORM VARYING WX-MM-8 FROM 12 BY -1
UNTIL MM-DIAS(WX-MM-8) < WX-DDD-JUL
END-PERFORM
*--- EL RESTO DE DDD SON LOS DIAS DENTRO DEL MES
SUBTRACT MM-DIAS(WX-MM-8) FROM WX-DDD-JUL GIVING WX-DD-8
DISPLAY 'FECHA AAAAMMDD:' WX-FECHA-GREG
STOP RUN
.
Por supuesto puede haber otras maneras de hacer estos cambios. Existen también funciones intrínsecas de COBOL que hacen la transformación, pero normalmente no dejan usarlas porque consumen muchos recursos.