Calcolo durata fra due 'timestamp' in COBOL

di il
21 risposte

Calcolo durata fra due 'timestamp' in COBOL

Ciao a tutti ed un ringraziamento in anticipo a quanti mi dedicheranno un po' di tempo.
Ho questo ambiente:
s.o. i5/OS v. 7.3 in IBM Power System
compilatore ILE COBOL.
Siamo in ambito assicurativo dove la durata della copertura di una polizza decorre da una certa data e ora ad un'altra data e ora.
Devo calcolare la durata in MESI fra due date espresse nel formato timestamp (di lunghezza 19).

In WS ho i seguenti campi:

77  W-TZE-I           FORMAT TIME "%H.%M.%S" VALUE "00.00.00".
    03 W-DURADA         FORMAT DATE "%Y%m%d". 
    03 W-DURAA        FORMAT DATE "%Y%m%d".
    03 W-DA           FORMAT TIMESTAMP SIZE 19.   
    03 W-AL           FORMAT TIMESTAMP SIZE 19.
    03 W-MESI         PIC S9(5).
Il valore di W-DURADA è "2020-01-01"
Il valore di W-DURAA è "2022-01-01"

Calcolo:

MOVE W-DURADA TO W-DA                                    
MOVE W-TZE-I  TO W-DA                                    
MOVE W-DURAA  TO W-AL                                    
MOVE W-TZE-I  TO W-AL                                    
MOVE FUNCTION SUBTRACT-DURATION(W-AL MINUTES 1) TO W-AL
Tolgo un minuto per garantirmi il calcolo corretto quando le due date hanno mm e gg uguali (01/01/2020 - 01/01/2022)

a questo punto
il valore di W-DA è '2020-01-01-00.00.00'
il valore di W-AL è '2021-12-31-23.59.00'

e procedo al calcolo della durata:

COMPUTE W-MESI   = 1 +                                   
           FUNCTION FIND-DURATION(W-DA W-AL MONTHS)
Il valore di W-MESI risulta 01363 invece di 24. Perchè?

Se il calcolo lo faccio direttamente fra W-DURADA e W_DURAA il valore che ottengo è 25 (12 mesi del '20, 12 mesii del '21' e Gennaio del '22 anche se per un solo giorno).
Possibile che abbia beccato un bug del compilatore o c'è qualche recondita regola che non conosco?
Grazie 1.000.000 a tutti.

21 Risposte

  • Re: Calcolo durata fra due 'timestamp' in COBOL

    Curiosità mia : la funzione datediff è supportata ?
    link : https://www.ibm.com/support/pages/how-calculate-difference-between-two-dates-resulting-days-months-or-years
  • Re: Calcolo durata fra due 'timestamp' in COBOL

    No, l'equivalente è la funzione FIND-DURATION.
  • Re: Calcolo durata fra due 'timestamp' in COBOL

    COBOL_Forever ha scritto:


    
    MOVE W-DURADA TO W-DA                                    
    MOVE W-TZE-I  TO W-DA                                    
    MOVE W-DURAA  TO W-AL                                    
    MOVE W-TZE-I  TO W-AL                                    
    MOVE FUNCTION SUBTRACT-DURATION(W-AL MINUTES 1) TO W-AL
    
    Premessa doverosa : ho abbandonato il Cobol circa 30 anni fa ... quindi posso avere ricordi solo confusi.
    A me sembra che le move che fai siano errate, ovvero :
    muovi un campo Date in un timestamp e successivamente muovi un campo Time nello stesso campo timestamp
    Magari il Cobol moderno ti permette queste move ed è in grado di allineare/concatenare i 2 campi di partenza in quello di arrivo, quello che ricordo io sicuramente non permetteva operazioni simili (a dire il vero non c'era neanche il tipo di dato timestamp).
  • Re: Calcolo durata fra due 'timestamp' in COBOL

    A me sembra che le move che fai siano errate, ovvero :
    muovi un campo Date in un timestamp e successivamente muovi un campo Time nello stesso campo timestamp
    Magari il Cobol moderno ti permette queste move ed è in grado di allineare/concatenare i 2 campi di partenza in quello di arrivo, quello che ricordo io sicuramente non permetteva operazioni simili (a dire il vero non c'era neanche il tipo di dato timestamp).
    Beh, in trent'anni anche il COBOL ha subito qualche modifichina.
    Le move che faccio sono corrette. Tant'è vero che ho verificato il contenuto delle variabili:
    
    il valore di W-DA è '2020-01-01-00.00.00'
    il valore di W-AL è '2021-12-31-23.59.00'
    
    In campo TIMESTAMP puoi muovere separatamente un campo DATE ed uno TIME senza che una move ricopra l'altra.

    Grazie della risposta.
  • Re: Calcolo durata fra due 'timestamp' in COBOL

    COBOL_Forever ha scritto:


    In campo TIMESTAMP puoi muovere separatamente un campo DATE ed uno TIME senza che una move ricopra l'altra.
    Non c'è più il Cobol di una volta

    Suggerimenti stupidi :
    - ottieni lo stesso risultato (con segno invertito) se inverti i 2 operandi timestamp nella funzione FIND_DURATION ?
    - ottieni lo stesso risultato se utilizzi FIND-DURATION con 2 campi data (date NO datetime) ?
  • Re: Calcolo durata fra due 'timestamp' in COBOL

    Premesso che ho lavorato per anni con AcuCobol (che non c'entra nulla con IBM), quindi quanto dico può essere una cavolata.

    Ad ogni modo, la funzione FIND_DURATION la usi nel modo corretto, almeno stando alla documentazione IBM, per cui il problema deve essere altrove.

    Quello che non mi è chiaro è il formato che stai dando alle date.

    Nelle ore hai messo i punti di separazione:
    FORMAT TIME "%H.%M.%S"
    Fra ore, mesi e secondi c'è il punto.


    Quando definisci le date, invece, il separatore manca:
    FORMAT DATE "%Y%m%d"

    Può essere che questa mancanza crei qualche tipo di problema?
  • Re: Calcolo durata fra due 'timestamp' in COBOL

    - ottieni lo stesso risultato (con segno invertito) se inverti i 2 operandi timestamp nella funzione FIND_DURATION ?
    - ottieni lo stesso risultato se utilizzi FIND-DURATION con 2 campi data (date NO datetime) ?
    Dal 'Reference' dell'IBM:
    FUNCTION FIND-DURATION ( argument-1 argument-2 argument-3 )

    argument-1, argument-2 Must be a date, time, or timestamp item.
    Argument-1 is subtracted from argument-2. The value returned is the number of complete units of
    argument-3. If argument-1 is later than argument-2, the result is negative. If argument-1 is earlier
    than argument-2, the result is positive.
    Se inverto le date il valore che ottengo è negativo
    Le date da elaborare possono essere una qualunque combinazione di: due date, una data ed un timestamp, due timestamp, due orari, un orario ed un timestamp.

    Se uso solo due campi data (e perdo le informazioni dell'orario di inizio e fine) ottengo un valore corretto.
  • Re: Calcolo durata fra due 'timestamp' in COBOL

    
    Quello che non mi è chiaro è il formato che stai dando alle date.
    
    Il compilatore provvede a de-editare i valori prima di fare il confronto. L'importante è che i campi sino definiti con FORMAT (non con PIC) TIME o DATE o TIMESTAMP.

    Comunque i valori dei due timestamp da confrontare sono corretti (li ho verificati con il debug):
    
    il valore di W-DA è '2020-01-01-00.00.00'
    il valore di W-AL è '2021-12-31-23.59.00'
    
    e questo è l'unico formato ammesso per un timestamp, cioè con i trattini ed i punti di separazione.
  • Re: Calcolo durata fra due 'timestamp' in COBOL

    COBOL_Forever ha scritto:


    Se inverto le date il valore che ottengo è negativo
    Il che conferma quanto scritto nel manuale (che avevo letto prima di darti il suggerimento).

    COBOL_Forever ha scritto:


    Se uso solo due campi data (e perdo le informazioni dell'orario di inizio e fine) ottengo un valore corretto.
    Il che conferma che il problema è il timestamp oppure la formattazione del campo timestamp e non la funzione.
    Leggendo il manuale sembra che la formattazione del timestamp sia :
    'YYYY-MM-DD-HH.NN.SS' come da te riportato quindi non ho altre idee (sembra strano il separatore '-' tra data e ora ma pare che sia proprio così).

    Visto che la funzione Find-duration accetta anche formati di data misti potresti provare :
    - Find-duration (DataInizio TimestampFine Months)
    - Find-duration (TimestampInizio DataFine Months)
    magari riesci ad identificare se il problema è legato al timestamp iniziale a quello finale oppure a entrambi

    Potresti anche provare ad usare dei timestamp SENZA l'impostazione dell'orario ...

    Oltre non saprei cosa indicarti.
  • Re: Calcolo durata fra due 'timestamp' in COBOL

    @max.riservo
    Grazie dei suggerimenti.
    Tra data ed orario nel timestamp qualcosa dovevano metterci ... hanno optato per il trattino!

    Sono quasi convinto che sia un bug del compilatore a carico della funzione FIND-DURATION per i seguenti motivi:
    1 i campi W-DA e W-AL contengono valori corretti per il formato TIMESTAMP
    2 nel manuale c'è scritto che posso confrontare due TIMESTAMP
    Rimane solo un dubbio, il compilatore accetta campi TIMESTAMP lunghi 19 chr o un valore compreso fra 23 e 26 (gestisce anche le frazioni di secondo): potrebbe essere che con la lunghezza massima la funzione calcoli in modo corretto. Se così fosse sarebbe comunque un baco del compilatore.

    Grazie mille.
  • Re: Calcolo durata fra due 'timestamp' in COBOL

    COBOL_Forever ha scritto:


    Tra data ed orario nel timestamp qualcosa dovevano metterci ... hanno optato per il trattino!
    Ha un suo perché ... in altri linguaggi si usa lo spazio (che può risultare non così evidente).

    COBOL_Forever ha scritto:


    Sono quasi convinto che sia un bug del compilatore a carico della funzione FIND-DURATION per i seguenti motivi:
    1 i campi W-DA e W-AL contengono valori corretti per il formato TIMESTAMP
    2 nel manuale c'è scritto che posso confrontare due TIMESTAMP
    Rimane solo un dubbio, il compilatore accetta campi TIMESTAMP lunghi 19 chr o un valore compreso fra 23 e 26 (gestisce anche le frazioni di secondo): potrebbe essere che con la lunghezza massima la funzione calcoli in modo corretto. Se così fosse sarebbe comunque un baco del compilatore.
    Potresti provare quindi aggiungendo la frazione di secondo valorizzata a zero, giusto per toglierti il dubbio.
    Potresti anche provare con altre date per verificare che tu non sia incappato in condizioni limite, non gestite correttamente (i.e. inizio anno/fine anno).

    Per il resto non ti resta che contattare AI.BI.EM. e segnalare il problema ... auguri & buona fortuna

    Alcune riflessioni tanto per dire qualcosa :
    - è proprio necessario gestire anche l'orario?
    - la non indicazione dell'orario potrebbe portarti all'errore di calcolo di 1 mese, visto che la tua unità di misura è il mese. Però i mesi hanno lunghezza variabile quindi anche l'indicazione del risultato espressa in mesi presenta un certo grado di incertezza. Potrebbe aver senso calcolare la differenza delle date in giorni e poi dividere il risultato per la durata 'convenzionale' di un mese (con convenzione da decidere) per esempio di 30 giorni ? Probabilmente no però potrebbe essere una strada esplorare.
    - la funzione Find-duration restituisce un intero (credo con troncamento e non arrotondamento alla cifra superiore - ma è da verificare sul manuale) quindi comunque c'è un margine di approssimazione (ie. 1mese e 27 giorni di differenza dovrebbe restituirti come risultato 1 mese) tale da far pensare che l'orario possa essere omesso ...
  • Re: Calcolo durata fra due 'timestamp' in COBOL

    - è proprio necessario gestire anche l'orario?
    Eh sì, come dicevo all'inizio del post in ambito assicurativo la durata della copertura di una polizza va da una certa data e ora ad un'altra data e ora.
    Esempio:
    Tra 01-01-2020 ore 15.00.00 e 01-01-2022 ore 14.59.00 ci sono 24 mesi o 731 giorni
    Tra 01-01-2020 ore 15.00.00 e 01-01-2022 ore 15.00.00 ci sono 25 mesi o 732 giorni.

    In ogni caso proverò a calcolare separatamente date e orari e poi fare una qualche somma sulla quale devo ancora ragionare.

    Dispiace comunque che la funzione abbia questo baco, dimenticavo di dire che se invece di chiedere il calcolo in mesi lo chiedo in giorni la FIND-DURATION dà sempre risultati corretti qualunque sia la combinazione di formati.
    Per il resto non ti resta che contattare AI.BI.EM. e segnalare il problema
    Sono sicuro che HAL-9000 è più affidabile

    Grazie mille per il tuo tempo.
  • Re: Calcolo durata fra due 'timestamp' in COBOL

    COBOL_Forever ha scritto:


    Eh sì, come dicevo all'inizio del post in ambito assicurativo la durata della copertura di una polizza va da una certa data e ora ad un'altra data e ora.
    Esempio:
    Tra 01-01-2020 ore 15.00.00 e 01-01-2022 ore 14.59.00 ci sono 24 mesi o 731 giorni
    Tra 01-01-2020 ore 15.00.00 e 01-01-2022 ore 15.00.00 ci sono 25 mesi o 732 giorni.
    Comprendo ... comprendo anche che per un minuto in più estendi la copertura di un mese che sicuramente paghi e quindi, per correttezza nei confronti dell'utente, dovresti estendere la durata di un mese (dovresti aggiornare la data da 01-01-2022 15.00.00 a 01-02-2022 14.59.59) in modo da essere conforme all'unità di misura (il mese). Ma trattandosi di tematiche assicurative/bancarie forse questa cura verso il Cliente non è prevista

    Saluti
  • Re: Calcolo durata fra due 'timestamp' in COBOL

    Vi è qualcosa che non torna in riferimento alla funzione intrinseca FIND-DURATION.
    Nella documentazione è riportatato che la funzione numerica restituisce un valore intero (come data types).
    https://www.ibm.com/docs/en/ssw_ibm_i_72/rzase/sc092540.pdf
    Infatti è specificato che viene troncato il valore restituito quando questo non è un intero:

    Manuale ha scritto:


    If the returned value is not an integer, it is truncated. For example, the duration between March 17, 1997 and May 2, 1997 is 1.5 months. Since FIND-DURATION only returns an integer the .5 would be truncated, and the actual value returned would be 1.
    https://www.ibm.com/docs/fr/i/7.3?topic=functions-find-duration#fndd
    https://www.ibm.com/docs/en/ssw_ibm_i_73/rzasb/sc092539.pdf

    Quindi è da circoscrivere solo l'operaziione della funzione FIND-DURATION, senza aggiungere elementi di calcolo, in modo da valutare ciò che viene restituito.
    In merito al calcolo è da tenere presente che la funzione FIND-DURATION quando ha per argomenti due valori di tipo TIMESTAMP accetta sino ai PICOSECONDS.
    Inoltre, nel caso dell'esempio sopra citato, per ottenere una durata di 24 mesi (dal momento che deve essere un valore intero) il calcolo con anche un minuto di differenza non permette il superamento del mese stesso.
    Quindi prima è determinare il corretto calcolo della durata (legato alla funione FIND-DURATION del COBOl) e dopo prendere in considerazione come questi devno essere espressi per l'ambiente assicurativo di riferimento.

    Aggiungo, visto il suggerimento:

    Max_riservo ha scritto:


    Per il resto non ti resta che contattare AI.BI.EM. e segnalare il problema ... auguri & buona fortuna
    che ho effettuato una ricerca del possinile errore della funzione FIND-DURATION ma il solo link trovato è il seguente:
    https://archive.midrange.com/cobol400-l/200907/msg00009.html
Devi accedere o registrarti per scrivere nel forum
21 risposte