1. Formatos de data no COBOL
O COBOL não tem um tipo nativo de data — datas são armazenadas como campos numéricos ou alfanuméricos. Os formatos mais comuns em produção:
WORKING-STORAGE SECTION. * AAAAMMDD — formato ISO, o mais comum em sistemas bancários 01 WS-DATA-ISO PIC 9(08). *ex: 20260615 * DDMMAAAA — formato BR para exibição 01 WS-DATA-BR PIC 9(08). *ex: 15062026 * AAMMDD — formato legado de 6 dígitos (cuidado com Y2K!) 01 WS-DATA-6 PIC 9(06). *ex: 260615 * Decomposta — campos separados 01 WS-DATA-DECOMPOSTA. 05 WS-ANO PIC 9(04). *2026 05 WS-MES PIC 9(02). *06 05 WS-DIA PIC 9(02). *15 * Formatada para exibição 01 WS-DATA-EXIBICAO X(10). *'15/06/2026' * Dia Lilian (dias desde 15/10/1582) — para aritmética 01 WS-LILIAN S9(09) COMP.
🦕 Analogia — data no COBOL é só um número disfarçado
No COBOL, 20260615 armazenado em PIC 9(08) é apenas o inteiro vinte milhões duzentos e sessenta mil seiscentos e quinze — o programa que decide ler isso como ano-mês-dia usando Reference Modification. Por isso datas em COBOL são tão fáceis de comparar (maior = mais recente) mas exigem cuidado ao fazer aritmética (não dá para simplesmente somar 30 ao campo e esperar que a data avance um mês corretamente).
2. FUNCTION CURRENT-DATE
FUNCTION CURRENT-DATE retorna a data e hora do sistema em um campo de 21 caracteres. É o jeito padrão de obter a data atual sem CALL externo:
WORKING-STORAGE SECTION. 01 WS-CURRENT-DATE PIC X(21). 01 WS-DATA-HORA REDEFINES WS-CURRENT-DATE. 05 WS-DH-ANO PIC 9(04). *posição 1-4 05 WS-DH-MES PIC 9(02). *posição 5-6 05 WS-DH-DIA PIC 9(02). *posição 7-8 05 WS-DH-HORA PIC 9(02). *posição 9-10 05 WS-DH-MIN PIC 9(02). *posição 11-12 05 WS-DH-SEG PIC 9(02). *posição 13-14 05 WS-DH-CENT PIC 9(02). *posição 15-16 (centésimos) 05 WS-DH-GMT-SINAL X(01). *posição 17 (+ ou -) 05 WS-DH-GMT-HH 9(02). *posição 18-19 05 WS-DH-GMT-MM 9(02). *posição 20-21 PROCEDURE DIVISION. * Captura data/hora atual MOVE FUNCTION CURRENT-DATE TO WS-CURRENT-DATE * Acessa campos individuais via REDEFINES DISPLAY 'Data: ' WS-DH-DIA '/' WS-DH-MES '/' WS-DH-ANO DISPLAY 'Hora: ' WS-DH-HORA ':' WS-DH-MIN ':' WS-DH-SEG * Monta data ISO para gravar no registro MOVE WS-CURRENT-DATE(1:8) TO WS-DATA-ISO * WS-DATA-ISO = '20260615'
3. Aritmética de datas — dia Lilian
Somar ou subtrair dias de uma data é a operação mais comum em sistemas de crédito: calcular vencimento, prazo de carência, dias em atraso. O caminho correto no COBOL é converter para dia Lilian (número inteiro de dias desde 15/10/1582), operar, e converter de volta:
WORKING-STORAGE SECTION. 01 WS-DATA-IN PIC X(08). *'20260615' AAAAMMDD 01 WS-FORMATO PIC X(08) VALUE 'YYYYMMDD'. 01 WS-LILIAN-IN S9(09) COMP. 01 WS-LILIAN-OUT S9(09) COMP. 01 WS-DATA-OUT PIC X(08). 01 WS-FC PIC X(12). *feedback code LE 01 WS-PRAZO-DIAS S9(09) COMP VALUE 30. PROCEDURE DIVISION. 1000-CALCULA-VENCIMENTO. * PASSO 1: converte data para dia Lilian CALL 'CEEDAYS' USING BY REFERENCE WS-DATA-IN BY REFERENCE WS-FORMATO BY REFERENCE WS-LILIAN-IN BY REFERENCE WS-FC END-CALL * PASSO 2: soma os dias de prazo COMPUTE WS-LILIAN-OUT = WS-LILIAN-IN + WS-PRAZO-DIAS * PASSO 3: converte Lilian de volta para data CALL 'CEEDATM' USING BY REFERENCE WS-LILIAN-OUT BY REFERENCE WS-FORMATO BY REFERENCE WS-DATA-OUT BY REFERENCE WS-FC END-CALL * WS-DATA-OUT = '20260715' (30 dias depois de 15/06/2026) 1100-DIAS-ENTRE-DATAS. * Diferença entre duas datas = diferença dos Lilianos CALL 'CEEDAYS' USING BY REFERENCE WS-DATA-INICIO BY REFERENCE WS-FORMATO BY REFERENCE WS-LIL-INICIO BY REFERENCE WS-FC END-CALL CALL 'CEEDAYS' USING BY REFERENCE WS-DATA-FIM BY REFERENCE WS-FORMATO BY REFERENCE WS-LIL-FIM BY REFERENCE WS-FC END-CALL COMPUTE WS-DIAS-ATRASO = WS-LIL-FIM - WS-LIL-INICIO.
✅ Por que não somar direto no campo de data?
Se você tem 20260131 (31 de janeiro) e soma 1, obtém 20260132 — que não é uma data válida. O dia Lilian evita esse problema: a soma de inteiros respeita automaticamente meses com diferentes quantidades de dias e anos bissextos. CEEDAYS e CEEDATM são rotinas do IBM Language Environment disponíveis em qualquer programa COBOL no z/OS.
4. Funções intrínsecas de data
O Enterprise COBOL oferece funções intrínsecas para datas que dispensam os CALLs ao LE em muitos casos:
* CURRENT-DATE — data/hora atual (21 chars) MOVE FUNCTION CURRENT-DATE TO WS-AGORA * INTEGER-OF-DATE — converte AAAAMMDD para inteiro (Gregoriano) * Similar ao Lilian, mas conta dias desde 31/12/1600 COMPUTE WS-INT-DATA = FUNCTION INTEGER-OF-DATE(WS-DATA-ISO) * DATE-OF-INTEGER — converte inteiro de volta para AAAAMMDD COMPUTE WS-DATA-ISO = FUNCTION DATE-OF-INTEGER(WS-INT-DATA + 30) * Soma 30 dias sem precisar de CALL ao LE! * INTEGER-OF-DAY / DAY-OF-INTEGER — usa formato AAADDD (dia juliano) COMPUTE WS-INT-DIA = FUNCTION INTEGER-OF-DAY(WS-DATA-JULIAN) * DAY-OF-WEEK — retorna 1(segunda) a 7(domingo) COMPUTE WS-DIA-SEMANA = FUNCTION MOD( FUNCTION INTEGER-OF-DATE(WS-DATA-ISO), 7 ) + 1 * WHEN-COMPILED — data de compilação do programa MOVE FUNCTION WHEN-COMPILED TO WS-DATA-COMPILACAO
| Função | Entrada | Saída | Uso |
|---|---|---|---|
CURRENT-DATE | — | X(21) | Data e hora do sistema |
INTEGER-OF-DATE | 9(8) AAAAMMDD | Inteiro | Converte para dia inteiro |
DATE-OF-INTEGER | Inteiro | 9(8) AAAAMMDD | Converte inteiro para data |
INTEGER-OF-DAY | 9(7) AAADDD | Inteiro | Data juliana para inteiro |
DAY-OF-INTEGER | Inteiro | 9(7) AAADDD | Inteiro para data juliana |
WHEN-COMPILED | — | X(21) | Data/hora da compilação |
5. Validando datas
WORKING-STORAGE SECTION. 01 WS-DATA-VAL 9(08). 01 WS-DATA-DEC REDEFINES WS-DATA-VAL. 05 WV-ANO 9(04). 05 WV-MES 9(02). 05 WV-DIA 9(02). 01 WS-DATA-OK X(01). 88 DATA-VALIDA VALUE 'S'. 01 WS-DIAS-MES. 05 VALUE 00. 05 VALUE 31. 05 VALUE 28. 05 VALUE 31. 05 VALUE 30. 05 VALUE 31. 05 VALUE 30. 05 VALUE 31. 05 VALUE 31. 05 VALUE 30. 05 VALUE 31. 05 VALUE 30. 05 VALUE 31. 01 WS-TAB-DIAS REDEFINES WS-DIAS-MES. 05 WS-MAX-DIA 9(02) OCCURS 13 TIMES. 01 WS-MAX-MES 9(02). PROCEDURE DIVISION. 9800-VALIDA-DATA. MOVE 'N' TO WS-DATA-OK * 1. Deve ser numérica IF WS-DATA-VAL IS NOT NUMERIC EXIT PARAGRAPH END-IF * 2. Mês entre 01 e 12 IF WV-MES < 1 OR WV-MES > 12 EXIT PARAGRAPH END-IF * 3. Máximo de dias do mês (tabela) MOVE WS-MAX-DIA(WV-MES) TO WS-MAX-MES * 4. Ajuste para ano bissexto (fev) IF WV-MES = 2 IF FUNCTION MOD(WV-ANO, 400) = 0 OR (FUNCTION MOD(WV-ANO, 4) = 0 AND FUNCTION MOD(WV-ANO, 100) NOT = 0) MOVE 29 TO WS-MAX-MES END-IF END-IF * 5. Dia entre 01 e máximo do mês IF WV-DIA < 1 OR WV-DIA > WS-MAX-MES EXIT PARAGRAPH END-IF MOVE 'S' TO WS-DATA-OK.
6. Exemplo completo
Sub-programa que recebe uma data de concessão e um prazo em dias, calcula o vencimento, valida a data resultante e retorna a data formatada para exibição:
IDENTIFICATION DIVISION. PROGRAM-ID. CALCVENC. DATA DIVISION. WORKING-STORAGE SECTION. 01 WS-FORMATO PIC X(08) VALUE 'YYYYMMDD'. 01 WS-LIL-IN S9(09) COMP. 01 WS-LIL-OUT S9(09) COMP. 01 WS-FC PIC X(12). 01 WS-DATA-NUM PIC 9(08). 01 WS-DATA-DEC REDEFINES WS-DATA-NUM. 05 WD-DIA 9(02). 05 WD-MES 9(02). 05 WD-ANO 9(04). LINKAGE SECTION. 01 LK-DATA-CONC PIC 9(08). *AAAAMMDD de concessão 01 LK-PRAZO-DIAS S9(09) COMP. 01 LK-DATA-VENC PIC 9(08). *AAAAMMDD de vencimento 01 LK-VENC-BR PIC X(10). *DD/MM/AAAA para exibição 01 LK-RETORNO PIC X(02). 88 VENC-OK VALUE '00'. 88 VENC-ERRO VALUE '01'. PROCEDURE DIVISION USING LK-DATA-CONC LK-PRAZO-DIAS LK-DATA-VENC LK-VENC-BR LK-RETORNO. 0000-INICIO. INITIALIZE LK-DATA-VENC LK-VENC-BR * Converte data de concessão para Lilian MOVE LK-DATA-CONC TO WS-DATA-NUM CALL 'CEEDAYS' USING BY REFERENCE LK-DATA-CONC BY REFERENCE WS-FORMATO BY REFERENCE WS-LIL-IN BY REFERENCE WS-FC END-CALL IF WS-FC(1:2) NOT = X'00F0' SET VENC-ERRO TO TRUE GOBACK END-IF * Soma prazo COMPUTE WS-LIL-OUT = WS-LIL-IN + LK-PRAZO-DIAS * Converte de volta para AAAAMMDD CALL 'CEEDATM' USING BY REFERENCE WS-LIL-OUT BY REFERENCE WS-FORMATO BY REFERENCE LK-DATA-VENC BY REFERENCE WS-FC END-CALL * Formata DD/MM/AAAA para exibição * LK-DATA-VENC = AAAAMMDD → extrai partes STRING LK-DATA-VENC(7:2) DELIMITED SIZE *DD '/' DELIMITED SIZE LK-DATA-VENC(5:2) DELIMITED SIZE *MM '/' DELIMITED SIZE LK-DATA-VENC(1:4) DELIMITED SIZE *AAAA INTO LK-VENC-BR END-STRING SET VENC-OK TO TRUE GOBACK.
7. Erros comuns
1. Aritmética direta em campo de data
* ERRADO: somar dias direto no campo AAAAMMDD MOVE 20260131 TO WS-DATA ADD 1 TO WS-DATA *resulta 20260132 — inválido! * CORRETO: converta para inteiro, some, converta de volta COMPUTE WS-INT = FUNCTION INTEGER-OF-DATE(WS-DATA) + 1 COMPUTE WS-DATA = FUNCTION DATE-OF-INTEGER(WS-INT) * WS-DATA = 20260201 (1 de fevereiro)
2. Comparar datas em formatos diferentes
* ERRADO: comparar DDMMAAAA com AAAAMMDD 01 WS-DATA-BR 9(08) VALUE 15062026. *DDMMAAAA 01 WS-DATA-ISO 9(08) VALUE 20260615. *AAAAMMDD IF WS-DATA-BR = WS-DATA-ISO *FALSO — números diferentes! * CORRETO: converta para um único formato antes de comparar * Prefira AAAAMMDD para armazenamento — ordena naturalmente IF WS-DATA-ISO-A < WS-DATA-ISO-B *AAAAMMDD compara corretamente como inteiro
3. Ano de 2 dígitos — problema Y2K ainda existe
* Sistemas legados ainda usam AAMMDD (6 dígitos) 01 WS-DATA-6 9(06) VALUE 260615. *AA=26? 1926 ou 2026? * Ao ler dado legado, aplique janela de pivô: IF WS-DATA-6(1:2) <= 50 STRING '20' WS-DATA-6 DELIMITED SIZE INTO WS-DATA-ISO ELSE STRING '19' WS-DATA-6 DELIMITED SIZE INTO WS-DATA-ISO END-IF * AA <= 50 → século 21 (2000-2050) * AA > 50 → século 20 (1951-1999) * Janela de pivô deve ser acordada com a equipe de negócio