Many mainframe records contain date fields—transaction dates, birth dates, effective dates—and you often need to keep or drop records based on those dates: for example, "keep only records from 2023," or "omit records before Jan 1, 2024." In DFSORT you do this with INCLUDE or OMIT and COND=, using the same comparison operators (EQ, NE, GT, GE, LT, LE) you use for other fields. The key is to use a date representation for which character or numeric order matches chronological order. The most common such format is YYYYMMDD (8 bytes: year, month, day). When the date is stored in that form, character (CH) comparison of the 8-byte string gives the same result as date order: "20230101" is less than "20231231". So you can use INCLUDE COND=(start,8,CH,GE,C'20230101') to keep records on or after that date. This page explains date filtering for YYYYMMDD and Julian (YYYYDDD), how to express date ranges, and what to do when the date is in a different format.
Dates in YYYYMMDD form (e.g. 20231225 for December 25, 2023) are written from the largest time unit (year) to the smallest (day). So when you compare two such strings byte-by-byte (as CH does), the result is the same as comparing the dates chronologically: an earlier date has a smaller string, a later date has a larger string. That is why you can use CH and the usual operators: GE keeps dates on or after the constant; LE keeps dates on or before; GT and LT exclude the boundary. No need to convert to a numeric date type for simple range filtering—just use the 8-byte character field and the right constant.
To keep records on or after a date (e.g. 20230101), use GE (greater than or equal). To keep records on or before a date, use LE. To keep records after a date (strictly), use GT; to keep records before a date (strictly), use LT. Assume the date is in positions 1–8 as YYYYMMDD:
1INCLUDE COND=(1,8,CH,GE,C'20230101')
This keeps every record whose date field is 20230101 or later. To omit records before 20240101:
1OMIT COND=(1,8,CH,LT,C'20240101')
So only records with date >= 20240101 are passed (OMIT drops those that are less than 20240101).
To keep records whose date is between two dates (inclusive), you need both: date >= start date and date <= end date. Combine the two conditions with AND:
1INCLUDE COND=(1,8,CH,GE,C'20230101',AND,1,8,CH,LE,C'20231231')
This keeps records in the year 2023 (from 20230101 through 20231231). Replace the start position (1) and length (8) with the actual position and length of your date field if different.
If the date is stored as Julian (year + day-of-year, e.g. 2023365 for the 365th day of 2023), the same idea applies: the string order of YYYYDDD is chronological. Use a 7-byte field for character Julian (e.g. 4 digit year + 3 digit day). Example: keep records on or after Julian 2023200 (day 200 of 2023):
1INCLUDE COND=(10,7,CH,GE,C'2023200')
If the Julian date is stored as numeric (PD/ZD), use the appropriate format and length and the numeric constant (e.g. 2023200).
| Format | Typical length | Note |
|---|---|---|
| YYYYMMDD | 8 | Character order = date order; use CH |
| YYYYDDD (Julian) | 7 | Character order = date order; use CH or numeric |
| DDMMYYYY or MMDDYYYY | Varies | Character order ≠ date order; convert to YYYYMMDD first |
Always use the start position and length that match your record layout. If the date is in the middle of the record (e.g. 25–32), use (25,8,CH,...) for YYYYMMDD.
If the date is stored as DDMMYYYY or MMDDYYYY, the character order of the string does not match date order. For example, 31122023 (31 Dec 2023) would collate before 01012024 (1 Jan 2024) in some orderings because the first bytes differ. In that case you have two options: (1) Use INREC (or a previous step) to build a new field in YYYYMMDD form from the existing date, then apply INCLUDE/OMIT on that new field. (2) Use DFSORT's date conversion or arithmetic features if your product supports them (see the Application Programming Guide for date conversion in INREC/OUTREC). For portability and clarity, converting to YYYYMMDD and then filtering is a solid approach.
If your input has the date in a different layout (e.g. separate month, day, year or DDMMYYYY), you can use INREC to build an 8-byte YYYYMMDD field (e.g. with BUILD or OVERLAY and date conversion operands). Then in INCLUDE you reference the position of that new field. The exact INREC syntax for date building depends on your product; see the manual. Once you have a single YYYYMMDD field, all the COND= examples on this page apply.
Imagine dates written as one long number: year, then month, then day (like 20231225). When we sort those numbers from smallest to biggest, the dates go from oldest to newest. So the computer can say "keep only the ones that are bigger than 20230101" and that means "keep only dates on or after January 1, 2023." We don't have to teach the computer what a calendar is—we just use the order of the digits. For dates written in a different order (like day-month-year), the order of the digits doesn't match the order of real dates, so we first rewrite them in year-month-day form, then do the same trick.
1. If a date is stored as YYYYMMDD in 8 character bytes (e.g. 20231225), how do you keep records on or after that date?
2. Why does YYYYMMDD work with character comparison?
3. If the date is stored as Julian (YYYYDDD), can you still use COND= to filter?
4. How do you keep records between two dates (inclusive) when both are YYYYMMDD?
5. What if the date is in a different format (e.g. DD/MM/YYYY or MMDDYYYY)?