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.
10 comentarios:
Bueno, yo creo que más bien quienes dicen eso en dichas instalaciones no tienen mucha idea, por varios motivos:
1) Las funciones intrínsecas una vez que las conocen son tan simples de usar como cualquier otra instrucción de COBOL.
2) Son más rápidas ya que el manejo de los datos de la fecha se hace a nivel de máquina usando directamente sus registros, no a alto nivel usando variables COBOL.
3) Y la más importante creo, seguro que siempre funciona de igual forma sin posibilidad de error a la hora de codificarla.
Añado un ejemplo:
...
...
01 FECHA1 PIC 9(08).
01 FECHA2 PIC 9(07).
...
...
MOVE FUNCTION CURRENT-DATE(1:8) TO FECHA1
COMPUTE FECHA2 =
FUNCTION DAY-OF-INTEGER(FUNCTION INTEGER-OF-DATE(FECHA1))
Aquí primero obtenemos la fecha del día en la variable FECHA1 y luego en FECHA2 obtenemos su equivalente en formato JULIANO y todo en una única línea, bueno dos si contamos la carga de FECHA1.
Pues sí Jose Antonio... pero quien manda manda!! jeje
Gracias por el ejemplo : )
Quería hacer una aportación a los algoritmos "De AAAAMMDD a AAAADDD", y "De AAAADDD a AAAAMMDD".
Falta un detalle en los bisiestos para que esté incompleto, ya que el cálculo de año bisiesto es:
Si es divisible por 4
Si es divisible por 100
Si es divisible por 400
SI es bisiesto
Si no
NO es bisiesto
fin SI
Si no
SI es bisiesto
fin Si
Si no
NO es bisiesto
fin Si
Perdón, se ha comido la indentación y creo que no se entiende nada, así que lo repito:
Quería hacer una aportación a los algoritmos "De AAAAMMDD a AAAADDD", y "De AAAADDD a AAAAMMDD".
Falta un detalle en los bisiestos para que esté incompleto, ya que el cálculo de año bisiesto es:
.Si es divisible por 4
. Si es divisible por 100
. Si es divisible por 400
. SI es bisiesto
. Si no
. NO es bisiesto
. fin SI
. Si no
. SI es bisiesto
. fin Si
.Si no
. NO es bisiesto
.fin Si
Bueno, a ver si a la tercera va la vencida!!!
Perdón, se ha comido la indentación y creo que no se entiende nada, así que lo repito:
Quería hacer una aportación a los algoritmos "De AAAAMMDD a AAAADDD", y "De AAAADDD a AAAAMMDD".
Falta un detalle en los bisiestos para que esté incompleto, ya que el cálculo de año bisiesto es:
.si es divisible por 4
....si es divisible por 100
.......si es divisible por 400
..........SI es bisiesto
.......si no
..........NO es bisiesto
.......fin si
....si no
.......SI es bisiesto
....fin si
.Si no
....NO es bisiesto
.fin si
Muchas gracias por la aportación! Lo revisaré cuando tenga un momento : )
Ese algoritmo no funciona para todos los años... mas bien tendriamos que hacer el algoritmo domsday, oye deberias de hacer un articulo para sumar fechas por que eso siempre nos da lata jaja al menos a mi siempre me da lata, luego tenemos las rutinas existentes para sumar fechas pero bueno me tope en una instalacion donde solo sumaba dias laborables y necesitaba dias naturales... bueno igual y si me lo permites yo hago el articulo
Todo tuyo Rodrigo! jaja
Anímate a hacerlo y lo sacamos : )
*--- COMPROBAR AÑO BISIESTO: RESTO = 0 = AÑO BISIESTO
DIVIDE WX-AAAA-JUL BY 100 GIVING WX-FIL9 REMAINDER WX-ANO-BIS
IF ANO-BIS-SI
DIVIDE WX-AAAA-JUL BY 400 GIVING WX-FIL9 REMAINDER WX-ANO-BIS
ELSE
DIVIDE WX-AAAA-JUL BY 4 GIVING WX-FIL9 REMAINDER WX-ANO-BIS
END-IF.
esté artículo me ayudó con un tp de la facu en assembler, dandome una idea para continuar, así que les dejo mi colaboración para el año bisiesto.
Saludos.
Muchas gracias Ariel!