MainframeMaster

Date Filtering with INCLUDE and OMIT

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.

INCLUDE / OMIT Advanced Filtering
Progress0 of 0 lessons

Why YYYYMMDD Works with Character Comparison

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.

Filtering by a Single Date

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:

text
1
INCLUDE COND=(1,8,CH,GE,C'20230101')

This keeps every record whose date field is 20230101 or later. To omit records before 20240101:

text
1
OMIT COND=(1,8,CH,LT,C'20240101')

So only records with date >= 20240101 are passed (OMIT drops those that are less than 20240101).

Date Ranges (Between Two Dates)

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:

text
1
INCLUDE 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.

Julian Date (YYYYDDD)

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):

text
1
INCLUDE 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).

Date Formats and Lengths

Common date formats and COND= usage
FormatTypical lengthNote
YYYYMMDD8Character order = date order; use CH
YYYYDDD (Julian)7Character order = date order; use CH or numeric
DDMMYYYY or MMDDYYYYVariesCharacter 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.

When the Date Format Is Not YYYYMMDD or YYYYDDD

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.

Using INREC to Build a YYYYMMDD Field

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.

Explain It Like I'm Five

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.

Exercises

  1. Write INCLUDE COND= to keep records where the date in positions 15–22 (YYYYMMDD) is in the year 2024 (Jan 1–Dec 31, 2024).
  2. Write OMIT COND= to drop records where the date at 1–8 is before 20200101.
  3. If the date is stored as Julian in positions 30–36 (7 bytes), write a condition to keep records on or after 2024001 (Jan 1, 2024).
  4. Why is CH comparison valid for YYYYMMDD but not for MMDDYYYY? Explain in one sentence.

Quiz

Test Your Knowledge

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?

  • Use PD format
  • Use CH format and COND=(start,8,CH,GE,C'20231225')—character comparison works for YYYYMMDD because the string order equals date order
  • Use BI format
  • Dates cannot be filtered

2. Why does YYYYMMDD work with character comparison?

  • It does not
  • Because the format is big-endian: year, then month, then day. So lexicographic order of the 8-byte string matches chronological order.
  • Only in EBCDIC
  • Only for GE

3. If the date is stored as Julian (YYYYDDD), can you still use COND= to filter?

  • No
  • Yes—same idea: 7-byte character (or numeric) YYYYDDD has string order = date order; use CH or PD/ZD with appropriate length
  • Only with INREC first
  • Only OMIT

4. How do you keep records between two dates (inclusive) when both are YYYYMMDD?

  • One INCLUDE with OR
  • INCLUDE COND=(start,8,CH,GE,C'date1',AND,start,8,CH,LE,C'date2')
  • Two INCLUDE statements
  • Use OUTREC

5. What if the date is in a different format (e.g. DD/MM/YYYY or MMDDYYYY)?

  • CH comparison still works for any format
  • Character order may not match date order—e.g. 31122023 vs 01012023; you may need INREC to convert to YYYYMMDD first, then filter
  • Use PD only
  • DFSORT cannot filter those