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:

COBOL Declarações de data mais usadas
       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:

COBOL FUNCTION CURRENT-DATE
       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:

COBOL Aritmética de datas com dia Lilian
       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:

COBOL Funções intrínsecas de data
             * 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çãoEntradaSaídaUso
CURRENT-DATEX(21)Data e hora do sistema
INTEGER-OF-DATE9(8) AAAAMMDDInteiroConverte para dia inteiro
DATE-OF-INTEGERInteiro9(8) AAAAMMDDConverte inteiro para data
INTEGER-OF-DAY9(7) AAADDDInteiroData juliana para inteiro
DAY-OF-INTEGERInteiro9(7) AAADDDInteiro para data juliana
WHEN-COMPILEDX(21)Data/hora da compilação

5. Validando datas

COBOL Rotina de validação de data AAAAMMDD
       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:

COBOL Sub-programa CALCVENC — calcula e formata vencimento
       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

COBOL Nunca some dias direto no 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

COBOL Padronize o formato antes de comparar
             * 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

COBOL Cuidado com datas legadas de 6 dígitos
             * 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