COBOL DATATYPE CONVERSION: Convert date in DDMMYY to a packed decimal of 3-bytes

2.5k Views Asked by At

I have a requirement where I want to move a date(DDMMYY) in numeric format into a packed decimal/ comp-3 of 3 bytes. the date have to be moved into an file where only 3 characters/bytes are allocated for it. This is what I tried.

 03  WD-DDMMYY-DT-NUMERIC         PIC 9(06).      
 03  WD-DDMMYY-DT-COMP3           PIC S9(06) COMP-3.
 03  WD-DDMMYY-REDF  REDEFINES WD-DDMMYY-DT-COMP3.
     05  WD-3CHARS-DT-COMP3       PIC X(03).      
     05  FILLER                   PIC X(01).    


Move WD-DDMMYY-DT-NUMERIC         to  WD-DDMMYY-DT-COMP3  
Move WD-3CHARS-DT-COMP3           to  file-variable -->  X(03)         

I am not getting the desired value in the output. how can it be done?

3

There are 3 best solutions below

0
On
01 WORKING-VARIABLES.
 03  WD-DDMMYY-DT-NUMERIC         PIC 9(06).      
 03  WD-3CHARS-DT-COMP3-X.
     05 WD-DDMMYY-DT-COMP3        PIC 9(08) COMP-3.
 03  FILLER REDEFINES WD-3CHARS-DT-COMP3-X.
     05 FILLER                    PIC X(01).
     05 WD-3CHARS-DT-COMP3        PIC X(03).


MOVE 311216                     TO WD-DDMMYY-DT-NUMERIC.
MULTIPLY WD-DDMMYY-DT-NUMERIC
  BY 10                     GIVING WD-DDMMYY-DT-COMP3.
Move WD-3CHARS-DT-COMP3         to FILE-O-FIELD.

should solve your problem.

0
On

Bills answer is correct, but I will try and give a more visual answer using the date 150131 (31 Jan 2015)

if you declare the field as

  05  WD-DDMMYY-DT-NUMERIC             PIC 9(06) comp-3.  

then 150131 is stored in WD-DDMMYY-DT-NUMERIC as x'01 50 13 1c' which takes up 4 bytes. But if you declare the field like

  05  WD-DDMMYY-DT-NUMERIC             PIC 9(06)V9 comp-3.  
  05  FILLER    REDEFINES      WD-DDMMYY-DT-PD.
      10  WD-BCD                       PIC X(03).

then 150131 is stored in WD-DDMMYY-DT-NUMERIC as x'15 01 31 0c' which again takes up 4 bytes, but WD-BCD holds x'15 01 31' which holds all the date and is 3 bytes long

0
On

You'll also want to "unpack" your date later in another program, so using REDEFINES rather than a group with a subordinate packed-decimal:

       05  WD-DDMMYY-DT-NUMERIC             PIC 9(06).      
       05  WD-DDMMYY-DT-PD PACKED-DECIMAL   PIC 9(06)V9
                                              VALUE ZERO.
       05  FILLER 
             REDEFINES
               WD-DDMMYY-DT-PD.
           10  WD-BCD                       PIC X(03).
           10  FILLER                       PIC X.

       MOVE WD-DDMMYY-DT-NUMERIC     TO WD-DDMMYY-DT-PD
       MOVE WD-BCD                   TO wherever-you-want

The low-order half-byte (nybble) of a packed-decimal field indicates the operational sign (C for positive, D for negative, F for no operational sign, treated as positive - there are some Non-Preferred signs as well, A, B, E).

For the digits part of a packed-decimal, one digit takes one nybble.

For a packed-decimal, any given number of bytes will allow an odd number of digits to fit exactly. An even number of digits must always be preceded by a zero (you don't worry about that, the compiler does it for you).

To get six decimal digits "packed" into three bytes, you must ignore the sign (remembering that a nybble is used even for an unsigned field). This result is a convention called Binary Coded Decimal (BCD). COBOL has no native support for BCD, so you have to code. But not much.

To get the sign out of the way, you need to shift your digits to the left one nybble, whilst leaving your sign where it is. Leaving the sign alone is not a problem, COBOL does that for you. Shifting left is like a multiply by a power of 10. To shift one left, multiply by 10.

However, there is a neater way to arrange for the shift, which is to define the packed-decimal field to have one decimal place (V9). When your date, obviously an integer, is MOVEd to this field, the decimal part will be zero (one digit) and the date date will precede the zero.

It is worth noting that with IBM's Enterprise COBOL V5 any multiply or divide by a power of 10 is actually implemented as an appropriate shift.

Which will mean that the code generated by the V5 compiler will be very similar for the MULTIPLY by 10 and the MOVE to a field with one decimal place. Perhaps identical (I can't check).

To "unpack" the date:

       05  WD-DDMMYY-DT-NUMERIC             PIC 9(06).      
       05  WD-DDMMYY-DT-PD PACKED-DECIMAL   PIC 9(06)V9
                                              VALUE ZERO.
       05  FILLER 
             REDEFINES
               WD-DDMMYY-DT-PD.
           10  WD-BCD                       PIC X(03).
           10  FILLER                       PIC X.

       MOVE wherever-you-want        TO WD-BCD
       MOVE WD-DDMMYY-DT-PD          TO WD-DDMMYY-DT-NUMERIC

Note the VALUE ZERO in this definition. Such is the way that Enterprise COBOL works (up to V4.2 anyway) it is not actually necessary, but it is documentary to the programmer. The low-order byte (the fourth) is never changed from it's initial VALUE, meaning it always contains X'0F'. The compiler will actually "short-circuit" this, because it is going to force the output to be unsigned anyway, so doesn't need the sign from the source field.