fhg
Volume 6, Number 25 -- June 28, 2006

Query/400 Handles Zero Dates (Sort Of)

Published: June 28, 2006

Hey, Ted:

I have a file that has two dates that are stored in eight-digit numeric fields in YYYYMMDD format. Using Query/400, I wish to find the difference in days between the two dates. However, one of the date fields may contain values of zero. When I view the resulting data from the query on my display, Query/400 fills the difference field with plus signs if a date is zero. But when I direct the query's output to a disk file, the query ends abnormally. Is there a way to replace the zero date with some other value, such as the current date, the other date field, or a date far into the future?

--Robert


Let me offer my condolences, Robert. I'm sorry that you have to use Query/400, the product that IBM never got around to finishing, when there are so many better report tools on the market. I'm reminded of something my friend Cletus the Codeslinger is fond of saying: "Anybody who puts a Query/400 query into a production job stream should be shot and his lousy carcass thrown into the dumpster." Now that I've editorialized, let me answer your question.

Unlike real query products, Query/400 does not have any conditional capabilities. You cannot say, "if this condition is true, do this, or else do that." However, in certain circumstances, you can fake it out. Fortunately, yours is one such certain circumstance.

The trick is to load a numeric field with a value of 1 or 0, indicating whether a date is zero or not. You can use this 1 or 0 field as a multiplier to load another date into a field.

Let's say the two dates in the file are PROMISEDT (the date we promised to ship an order to a customer) and SHIPDT (the date the order was shipped.) The promise date is always a valid date, but the ship date is zero if the order has not shipped. These zero ship dates exemplify the type of problem you describe.

Let's write a query to determine the number of days between the promise date and the ship date. We'll use a positive number to indicate that the order shipped late, a negative number to indicate that the order shipped early, and zero will mean that the order shipped right on time.

What should we do with the zero ship dates? You mentioned three possibilities. I don't suppose it matters which one we consider first, so let's begin by treating zero dates as some date far into the future. Orders that have not shipped will stick out like a sore thumb because they will appear to be thousands of days late.

Here are the necessary result fields. The last one, which I cleverly named LATE, is the difference between SHIPDT and PROMISEDT. Notice that the column heading entry blank contains comments about the result fields. This is one way to include comments in a query. The real column headings are defined under the Specify report column formatting option.

Field       Expression                         Column Heading        Len   Dec
SDNOT0      shipdt/(shipdt-0.0000001)          0=Ship date is zero     1     0
                                               1=ship date is not             
                                               zero                           
                                                                               
SDIS0       (sdnot0-1)*(sdnot0-1)              0=Shp date is not       1     0
                                               zero, 1=ship date is           
                                               zero                           

ADJSHIPDT   shipdt+(sdis0*20390101)            Adjusted ship date      8     0
                                               If zero, use Jan 1,            
                                               2039 instead                   
                                                                              
PDIG        digits(promisedt)                  Convert promise date           
                                               to alpha                       

PDATE       date(substr(pdig,5,2)||'/'||       Convert promise date
            substr(pdig,7,2)||'/'||            to date             
            substr(pdig,3,2))                                      
                                                                   
SDIG        digits(adjshipdt)                  Convert adjusted   
                                               ship date to alpha  

SDATE       date(substr(sdig,5,2)||'/'||       Convert adjusted               
            substr(sdig,7,2)||'/'||            ship date to date              
            substr(sdig,3,2))                                                 
                                                                              
LATE        days(sdate)-days(pdate)            Number of days shipm           
                                               ent was late                   

The first result field is SDNOT0 (ship date is not zero). I determined whether ship date is not zero (1) or is zero (0) by dividing the ship date by itself minus a very small number and storing the result in a one-digit field.

The second result field is SDIS0 (ship date is zero.) This is the opposite of the SDNOT0. That is, if SDNOT0 is 1, SDIS0 is 0, and vice versa. I determined this field by subtracting one from SDNOT0 and squaring the answer. I'll leave it to you to figure out why that works, if you're curious.

The third result field, ADJSHIPDT (adjusted ship date), takes one of two values. If ship date is not zero, the adjusted ship date is the ship date value. The calculation in this case is ship date plus zero times a constant 20390101, which yields the ship date. If ship date is zero, adjusted ship date is January 1, 2039. The calculation is a zero ship date, plus one times 20390101.

The next four fields convert adjusted ship date and promise date into date fields (i.e., fields of the date data type), using a two-step process. The first step converts the numeric date to character. The second converts a character date to the date type. Notice that my system uses MM/DD/YY format.

The last field, LATE, finds the number of days difference. The DAYS function converts a date into an ordinal value, with day 1 being January 1 of the year 1 A.D.

Here's the result of the query with enough fields to show you what's going on.

PROMISEDT   SHIPDT SDNOT0 SDIS0 ADJSHPDT        LATE 
 20060501 20060501    1     0   20060501           0 
 20060501 20060502    1     0   20060502           1 
 20060501 20060430    1     0   20060430           1-
 20060501 00000000    0     1   20390101      11,933 
 20060430 20060601    1     0   20060601          32 

Notice that the record with the zero ship date is obvious because of the large value in LATE.

Now for the second option. If you want to substitute the current date for a zero date, your report shows how late, or how early, unshipped orders are. Here is the same query, with the necessary modifications.

Field       Expression                         Column Heading        Len   Dec
CURDT       year(current(date))*10000+         Current date            8     0
            month(current(date))*100+                                         
            day(current(date)) 
                                      
SDNOT0      shipdt/(shipdt-0.0000001)          0=Ship date is zero     1     0
                                               1=ship date is not             
                                               zero                           
SDIS0       (sdnot0-1)*(sdnot0-1)              0=Shp date is not       1     0
                                               zero, 1=ship date is           
                                               zero                           
                                                                              
ADJSHIPDT   shipdt+(sdis0*curdt)               Adjusted ship date      8     0
                                               If zero, use current            
                                               date instead                   

PDIG        digits(promisedt)                  Convert promise date
                                               to alpha            
                                                                   
PDATE       date(substr(pdig,5,2)||'/'||       Convert promise date
            substr(pdig,7,2)||'/'||            to date             
            substr(pdig,3,2))                                      

SDIG        digits(adjshipdt)                  Convert adjusted 
                                               ship date to alpha
                                                                 
SDATE       date(substr(sdig,5,2)||'/'||       Convert adjusted  
            substr(sdig,7,2)||'/'||            ship date to date 
            substr(sdig,3,2))                                    

LATE        days(sdate)-days(pdate)            Number of days shipm
                                               ent was late        

The first field retrieves the current date as an eight-digit number in YYYYMMDD format. The other difference between this version and the first one is in the way adjusted sales date is calculated. The January 1, 2039 literal has been replaced with the numeric current date. If the current date is June 21, 2006, the unshipped order is 51 days late, as the following query run shows.

PROMISEDT    SHIPDT  SDNOT0  SDIS0  ADJSHIPDT         LATE 
 20060501  20060501     1      0     20060501            0 
 20060501  20060502     1      0     20060502            1 
 20060501  20060430     1      0     20060430            1-
 20060501  00000000     0      1     20060621           51 
 20060430  20060601     1      0     20060601           32 

The third possibility you mentioned is to substitute the promise date for a zero ship date. The assumption is that unshipped orders will be shipped on time.

The only change necessary is in adjusted ship date. If ship date is not zero, the calculation is the ship date plus zero times the promise date. If ship date is zero, the calculation is zero plus one times the promise date.

Field       Expression                         Column Heading        Len   Dec
SDNOT0      shipdt/(shipdt-0.0000001)          0=Ship date is zero     1     
                                               1=ship date is not            
                                               zero                          
                                                                             
SDIS0       (sdnot0-1)*(sdnot0-1)              0=Shp date is not       1     
                                               zero, 1=ship date is          
                                               zero                          
ADJSHIPDT   shipdt+(sdis0*promisedt)           Adjusted ship date      8     0
                                               If zero, use promise           
                                               date instead                   
                                                                              
PDIG        digits(promisedt)                  Convert promise date           
                                               to alpha                       

PDATE       date(substr(pdig,5,2)||'/'||       Convert promise date
            substr(pdig,7,2)||'/'||            to date             
            substr(pdig,3,2))                                      
                                                                   
SDIG        digits(adjshipdt)                  Convert adjusted   
                                               ship date to alpha  

SDATE       date(substr(sdig,5,2)||'/'||       Convert adjusted    
            substr(sdig,7,2)||'/'||            ship date to date   
            substr(sdig,3,2))                                      
                                                                   
LATE        days(sdate)-days(pdate)            Number of days shipm
                                               ent was late        

Here's the result of the query.

PROMISEDT    SHIPDT  SDNOT0  SDIS0  ADJSHIPDT         LATE 
 20060501  20060501     1      0     20060501            0 
 20060501  20060502     1      0     20060502            1 
 20060501  20060430     1      0     20060430            1-
 20060501  00000000     0      1     20060501            0 
 20060430  20060601     1      0     20060601           32 

Well, Robert, it's not elegant, but it works. Good luck!

--Ted



Sponsored By
T.L. ASHFORD

BARCODE400 by T.L. Ashford is the easiest, fastest way to create and print Compliance Labels directly from the AS/400 and iSeries.

Ashford's comprehensive library of Compliance formats is available to Barcode400 users. AIAG labels for Ford and Motorcraft, GM, and many more are available.

BARCODE400 is backed by the best Technical Support Team in the industry.

FREE Guide to Bar Code Labeling
www.tlashford.com
or call 800.541.4893



Senior Technical Editor: Ted Holt
Technical Editors: Howard Arner, Joe Hertvik, Shannon O'Donnell, Kevin Vandever
Contributing Technical Editors: Joel Cochran, Wayne O. Evans, Raymond Everhart,
Bruce Guetzkow, Brian Kelly, Marc Logemann, David Morris
Publisher and Advertising Director: Jenny Thomas
Advertising Sales Representative: Kim Reed
Contact the Editors: To contact anyone on the IT Jungle Team
Go to our contacts page and send us a message.

Sponsored Links

ASNA:  DataGate for access to OS/400 DB2 UDB and SQL Server from any .NET application
COMMON:  Join us at the Fall 2006 conference, September 17-21, in Miami Beach, Florida
Integrated Print Solutions:  Print AFP/IPDS documents to any network printer

 


 
Subscription Information:
You can unsubscribe, change your email address, or sign up for any of IT Jungle's free e-newsletters through our Web site at http://www.itjungle.com/sub/subscribe.html.

Copyright © 1996-2008 Guild Companies, Inc. All Rights Reserved.
Guild Companies, Inc., 50 Park Terrace East, Suite 8F, New York, NY 10034

Privacy Statement