Zoned decimal (ZD) in DFSORT is the format you use when your sort key is stored in zoned decimal form: one digit per byte, with the high nibble of each byte holding the "zone" (typically X'F' in EBCDIC) and the low nibble holding the digit (0–9). The sign is usually encoded in the last byte (the rightmost byte)—the high nibble of that byte indicates positive (e.g. F or C) or negative (e.g. D). This is exactly 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 1 sorts before 2, 9 before 10, and negative numbers sort before positive in ascending order. This page explains the zoned decimal byte layout, when to use ZD, how sign and length work, and how it differs from character (CH) and packed decimal (PD) sorting.
Zoned decimal is a way of storing decimal numbers in which each digit uses one byte. In EBCDIC, the byte for the digit "5" is typically X'F5': the high nibble F is the "zone," and the low nibble 5 is the digit. So the number 12345 stored in zoned decimal is five bytes: X'F1F2F3F4F5' (positive, no explicit sign in this unsigned form). For a signed number, the last byte carries the sign in the high nibble: for example, +12345 might be X'F1F2F3F4C5' (C = positive) and -12345 might be X'F1F2F3F4D5' (D = negative in EBCDIC). COBOL calls this USAGE DISPLAY; the PIC clause might be PIC S9(5) DISPLAY. DFSORT uses the code ZD to mean "interpret this key as a signed zoned decimal number and compare by numeric value."
Use ZD whenever the sort key in your record is stored in zoned decimal (display) form. That includes: (1) COBOL fields defined as PIC 9(n) or S9(n) with USAGE DISPLAY (or no USAGE, which defaults to DISPLAY for numeric); (2) Any numeric field written by an application as one character (or one EBCDIC digit) per byte with a sign in the last (or first) byte; (3) Legacy files where the layout documentation says the field is "display" or "zoned." Do not use ZD for packed decimal (COMP-3)—use PD for that. Do not use ZD for binary (COMP)—use BI or FI. If you use ZD on packed or binary data, DFSORT will misinterpret the bytes and the sort order will be wrong.
In a zoned decimal byte, the high nibble (first 4 bits) is the zone. For valid digits in EBCDIC this is usually X'F'. The low nibble (last 4 bits) is the digit (0–9). So bytes X'F0' through X'F9' represent the characters "0" through "9". For a signed field, the rightmost byte (low-order byte) also encodes the sign in its high nibble: in EBCDIC, C and F typically mean positive, D means negative. So the value -5 might be stored as a single byte X'D5' (sign D, digit 5). DFSORT, when using ZD, reads the full key length, interprets the whole thing as a signed decimal number (including the sign in the last byte), and compares two keys by their numeric value. So -10 is less than -5, which is less than 0, which is less than 5.
For ZD, the length you specify in SORT FIELDS= is the number of bytes the key occupies. Because zoned decimal uses one byte per digit, a 5-digit field has length 5; a 10-digit field has length 10. The position is the starting byte (1-based). So for a 5-byte zoned decimal field starting at position 21, you would code SORT FIELDS=(21,5,ZD,A) for ascending numeric order. The key must fit entirely within the record: position + length - 1 must not exceed the record length (or the INREC output length if INREC is used).
In COBOL, the sign can be trailing (in the last byte) or leading (in the first byte), or stored separately, depending on the program and data definition. Most often you see trailing sign: the rightmost byte has the sign in the high nibble and the units digit in the low nibble. DFSORT ZD is designed to handle the standard EBCDIC zoned representation; if your data uses a different sign convention (e.g. leading sign or separate sign byte), you may need to ensure the data matches what DFSORT expects or use INREC to normalize the field. When in doubt, check the copybook or program that writes the data. For typical trailing-sign EBCDIC zoned decimal, ZD works as described.
If a field contains zoned decimal data (e.g. X'F1F2F3F4C5' for +12345), using CH would compare those bytes in EBCDIC order, byte by byte. For positive same-length digit strings, the order often matches numeric order because the character codes for 0–9 are in order. But the sign byte (C vs D vs F) would be compared as a character, so negative numbers might not sort in the correct numeric position relative to positive numbers. Using ZD tells DFSORT to interpret the bytes as a number, so the comparison is by numeric value: -99999, -1, 0, 1, 99999 in ascending order. So for any field that is logically a number stored in zoned form, use ZD so that the sort order is correct for negative values and for all magnitudes.
Packed decimal (PD) stores two digits per byte (plus sign in the last nibble). So the number 12345 in packed form might be X'12345C' (3 bytes). In zoned decimal (ZD), 12345 is X'F1F2F3F4F5' or similar (5 bytes). The byte layouts are completely different. If your data is stored in zoned form (one byte per digit) and you specify PD, DFSORT will try to read two digits per byte and will get garbage—wrong sort order or meaningless comparison. If your data is stored in packed form and you specify ZD, DFSORT will treat each byte as one digit and again get wrong order. Always match the format to the storage: DISPLAY / zoned → ZD; COMP-3 / packed → PD.
Sort by a 5-byte zoned decimal quantity at position 30, ascending:
1SORT FIELDS=(30,5,ZD,A)
Sort by bytes 1–10 character, then by bytes 11–15 zoned decimal descending (e.g. name then amount):
1SORT FIELDS=(1,10,CH,A,11,5,ZD,D)
In the second example, the first key is character (e.g. customer name) and the second is a 5-byte zoned decimal field (e.g. amount in display form). Records are ordered by name A–Z, and within the same name by amount highest first (descending).
When you are not sure whether a field is zoned or packed, look at the COBOL copybook or the program that writes the file. A field defined as PIC S9(7) DISPLAY or PIC 9(5) (default DISPLAY) is zoned decimal—use ZD and length 7 or 5 respectively. A field defined as PIC S9(7) COMP-3 is packed decimal—use PD and the byte length (e.g. 4 bytes for 7 digits + sign). Getting the format and length from the actual data definition avoids sort-order errors.
Zoned decimal is like writing a number with one digit in each box: the number 123 has one box with 1, one with 2, one with 3. The sort program needs to know "this is that kind of number" so it can compare 123 and 99 correctly (123 is bigger). If the program thought the boxes were just letters, it might compare the first box and get the order wrong. So we tell the sort "ZD" so it reads the boxes as a real number and puts them in order from smallest to biggest (or biggest to smallest).
1. What storage type does DFSORT ZD (zoned decimal) correspond to in COBOL?
2. In zoned decimal, how many bytes does a PIC 9(5) field occupy?
3. Where is the sign stored in standard EBCDIC zoned decimal?
4. If you sort a DISPLAY numeric field using CH instead of ZD, what can go wrong?
5. For SORT FIELDS with ZD, what does the length parameter mean?