Mostrando entradas con la etiqueta DDMMAAAA. Mostrar todas las entradas
Mostrando entradas con la etiqueta DDMMAAAA. Mostrar todas las entradas

lunes, 9 de mayo de 2011

Fechas: Juliana, Gregoriana, DB2...

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.