Frequently Asked Questions about SAS Software

The following Question & Answer List is based on SAS questions received by the author.

Date Processing with SAS Software

Question Answer
I have pairs of SAS date and time variables in a table, but I want to calculate the differences between them. Is there an easy way to do this? You can use the DHMS() function to combine SAS date and time variables into a SAS datetime variable. Note that SAS time variables actually contain the number of seconds elapsed since midnight, so you don't need to split up the time into hours, minutes and seconds first for DHMS(). The INTCK() function can then be used to calculate the difference between the 2 SAS datetime values:
DATA _null_;
  INFORMAT date1 date2 DATE9.
           time1 time2 TIME5.
           unit $10.;
  FORMAT dt1 dt2 DATETIME.;
  INPUT date1 time1 date2 time2 unit;
  dt1=DHMS(date1,0,0,time1);
  dt2=DHMS(date2,0,0,time2);
  difference=INTCK(unit,dt1,dt2);
  PUT unit= dt1= dt2= difference=;
  DATALINES;
21mar2003 21:05 22mar2003 00:30 SECOND
21mar2003 21:05 22mar2003 00:30 MINUTE
21mar2003 21:05 22mar2003 00:30 HOUR
21mar2003 21:05 24mar2003 10:25 DTDAY
21mar2003 21:05 22may2003 10:25 DTWEEK
21mar2003 21:05 22oct2004 10:25 DTMONTH
21mar2003 21:05 22jan2009 10:25 DTYEAR
;
RUN;
Warning: INTCK() returns the number of unit boundaries crossed, e.g. for HOUR, 21:59 to 22:01 = 1, but 21:01 to 21:59 = 0, because the former example crosses 22:00, but the latter has both values within the same hour.
How can I calculate the week of the year from a SAS date? You can simulate a WEEK function by using the SAS functions INTCK and INTNX, e.g.:
DATA getweek;
  datevar=TODAY();
  week=INTCK('WEEK',
             INTNX('YEAR',datevar,0),
             datevar)+1;
RUN;
I have a SAS table containing historical information in a single record:
id    startdate1   enddate1     startdate2   enddate2
001   01Jan2000    15Apr2002    28Jun2000    16Sep2001
002   01Feb2000    07Feb2002    19Jul2000    04Oct2000
How do I convert this data to multiple monthly summary records between the startdate1 and enddate1 values, and include extra information from startdate2 and enddate2.
It is not possible to directly use monthly dates in DO...END loops, as each months haa a varying number of days. However, you can still generate successive months by using the number of months relative to the startdate1 value using the INTCK and INTNX functions. The additional information can be calculated by comparing the values of the 1st day of the same month for each date:
DATA monthly (KEEP=id date month flag2);
  SET history;
  month_count=INTCK('MONTH',startdate1,enddate1);
  startmonth2=INTNX('MONTH',startdate2,0);
  endmonth2=INTNX('MONTH',enddate2,0);
  DO month=0 TO month_count;
    date=INTNX('MONTH',startdate1,month);
    IF startmonth2 LE date LE endmonth2
      THEN flag2=1;
      ELSE flag2=0;
    OUTPUT;
  END;
  FORMAT date MONYY7.;
RUN;
I want to select the previous 5 weekdays using an IN clause containing Julian date values, but I am forced to hardcode the values:
IF procdate IN (1997204,1997205,
                1997206,1997209,
                1997210)
  THEN DO;
    ......etc

Is there a way to automate this?

Probably the easiest way is to generate the previous weekdays, and then store the Julian date values in a SAS macro variable, e.g.:
DATA _null_;
  LENGTH datestr $42;
  datestr='(';
  DO d=(TODAY()-1) TO (TODAY()-7);
    IF (1 LT WEEKDAY(d) LT 7)
      THEN datestr=TRIM(datestr) !!
                   PUT(d,JULIAN7.) !! 
                   ',';
  END;
  SUBSTR(datestr,LEN(TRIM(datestr)),1)=')';
  CALL SYMPUT('datestr',TRIM(datestr));
  STOP;
RUN;

The macro variable can then be used to replace your list of dates, e.g.:

IF procdate IN &datestr
  THEN DO;
    ......etc
When I use INTCK('YEAR',birthday,TODAY()) to calculate someone's age it doesn't always give the correct answer. Am I doing something wrong? You should avoid using the INTCK function with 'YEAR' to calculate age, as it returns the number of times January 1st occurs between the 2 dates. Using 'MONTH' instead of 'YEAR' will give the number of 1st of the month days between the 2 dates, but this can be adjusted by comparing the day of the month of each date, e.g.:
DATA getage;
  birthday='25Dec1972'd;
  datevar=TODAY();
  /* Divide months by 12 to get years */
  age=INT(INTCK('MONTH',birthday,datevar)/12);
  /* Adjust age if the 2 dates have the same month */
  /* and the birthday is still to come in this month */
  IF MONTH(birthday)=MONTH(datevar) THEN
    age=age-(DAY(birthday)>DAY(datevar));
RUN;

     Back to Main FAQ Menu