In DFSORT, ZD stands for zoned decimal. A zoned decimal field stores one decimal digit per byte: each byte has a "zone" in the high nibble (often X'F' in EBCDIC) and the digit (0–9) in the low nibble. The sign is encoded in the last byte (or sometimes the first, depending on COBOL): the zone nibble indicates positive (e.g. F or C) or negative (e.g. D). This is how COBOL USAGE DISPLAY numeric data is stored (PIC 9(n) or S9(n) DISPLAY). When you specify ZD in SORT FIELDS, DFSORT interprets the key as a signed decimal number and compares numeric value—so 9 comes before 10, and negative numbers sort before positive in ascending order. Using CH on the same data compares raw bytes (character order), which can give wrong numeric order; using PD expects two digits per byte and is wrong for zoned data. This page explains ZD in detail: byte layout, sign, when to use ZD, and how it differs from CH, PD, and BI.
In zoned decimal, each byte represents one digit. The high nibble (first 4 bits) is the "zone"—in EBCDIC, X'F' is common for unsigned digits, and the zone is also used for the sign in the last byte. The low nibble (last 4 bits) holds the digit 0–9. So the number 12345 in zoned form is five bytes: X'F1', X'F2', X'F3', X'F4', X'F5' for positive (F in zone of each byte). In EBCDIC, F1 is the character "1", F2 is "2", and so on—so zoned decimal looks like the EBCDIC representation of the digit string. For a negative number, the last byte has the sign in the zone: D in the zone (e.g. X'D5') often means negative, so -12345 might be X'F1F2F3F4D5'. So zoned decimal is "one digit per byte" with sign in the last (or first) byte's zone. DFSORT ZD tells the sort to read the key as this format and compare the numeric value.
For zoned decimal, the length in SORT FIELDS is the number of bytes the field occupies. Since there is one digit per byte, a 5-digit field is 5 bytes, a 7-digit field is 7 bytes, and so on. The sign is in one of those bytes (usually the last), so you do not add an extra byte for sign—the last byte holds both the last digit and the sign.
| Digits (e.g. PIC 9(n) or S9(n)) | Bytes (length in SORT FIELDS) | Example |
|---|---|---|
| 5 | 5 | PIC S9(5) DISPLAY → 5 bytes |
| 7 | 7 | PIC 9(7) DISPLAY → 7 bytes |
| 8 | 8 | PIC S9(8) DISPLAY (e.g. date) → 8 bytes |
Use ZD in SORT FIELDS like this:
1SORT FIELDS=(start,length,ZD,direction)
Example: sort by a 5-byte zoned amount at position 25, ascending:
1SORT FIELDS=(25,5,ZD,A)
Example: sort by 8-byte date (YYYYMMDD) at position 1 then 4-byte zoned at 9, both ascending:
1SORT FIELDS=(1,8,ZD,A,9,4,ZD,A)
| Use case | Reason |
|---|---|
| COBOL DISPLAY numeric (PIC 9(n), S9(n)) | Storage is one digit per byte, sign in last byte. |
| Numeric data stored as EBCDIC digits | One character per digit; ZD interprets as number. |
| Dates or IDs stored as fixed-length digit strings with possible sign | ZD handles sign and leading zeros correctly. |
If a field contains only digits (and sign), you might think CH would work—and for fixed-length positive digit strings it sometimes does, because in EBCDIC the codes for 0–9 are in ascending order. But CH compares byte-by-byte and does not interpret the sign. A negative number has a different zone in the last byte (e.g. D); compared as character, that can sort in the wrong place relative to positive numbers. Also, if lengths ever differ (e.g. "9" vs "10"), CH puts "10" before "9" because the first byte "1" is less than "9" in EBCDIC. ZD interprets the whole field as one signed number, so 9 comes before 10 and negatives sort correctly. So for any zoned decimal numeric key, prefer ZD over CH for correct numeric order.
PD (packed decimal) stores two digits per byte. So the number 12345 in packed form is three bytes (X'12345C'), while in zoned form it is five bytes (X'F1F2F3F4F5'). If you use ZD on a packed field, DFSORT will treat those three bytes as a 3-digit zoned number and read the wrong value. If you use PD on a zoned field, it will expect two digits per byte and again get the wrong value. So you must know the actual storage: one digit per byte → ZD; two digits per byte (COMP-3) → PD.
In the last byte of a zoned decimal field, the low nibble is the last digit and the high nibble (zone) is the sign. Common EBCDIC conventions: F or C for positive, D for negative. Some COBOL variants use SIGN LEADING (sign in the first byte) or other encodings. DFSORT understands the usual conventions and compares the numeric value correctly. Negative numbers sort before zero, which sorts before positive, in ascending order.
Wherever DFSORT needs to interpret a numeric field—in INCLUDE/OMIT conditions or in INREC/OUTREC—you specify the format. For a zoned decimal field, use ZD so that numeric comparisons (e.g. greater than 100, equal to zero) and any arithmetic use the correct value. Using CH would compare the bytes as character; using PD would misinterpret the layout.
Imagine writing a number with one digit in each box: 1, 2, 3, 4, 5 in five boxes. The last box also has a little mark for plus or minus. That is zoned decimal. ZD is the rule that tells the sort: "this part of the record is a number written that way." So the sort puts the smaller numbers first (or bigger first) the way we expect: 9 before 10, and minus 5 before plus 5. If we used the "character" rule (CH), the sort would just look at the boxes as letters and might put 10 before 9. So we use ZD when the key is a number stored with one digit per box (like many numbers you see in mainframe files that look like normal digits when printed).
1. What does ZD mean in DFSORT?
2. A COBOL field is PIC S9(5) DISPLAY. What length do you specify in SORT FIELDS?
3. Where is the sign in standard EBCDIC zoned decimal?
4. When can CH give the same order as ZD for a numeric field?
5. What happens if you use ZD for a packed decimal (COMP-3) field?