 
 
 
 
 
   
     data msf;
        set crsp.msf(keep=permno date ret);
	year=year(date);
	month=month(date);
     run;
     proc sort data=msf;
        by permno year month;
     run;
     proc means data=msf;
        by permno year;
	var ret;
     run;
This is appealing when, say, you have to calculate within-year averages, but it can quickly get tedious if you have to do other simple tasks. For instance, suppose you want to create a series of *daily* dates from January 1, 1961 to December 31, 1962.
     data dates;
	 do year=1961 to 1962;
	    do month=1 to 12;
	       lengthofmonth=31;
    	       if month=4 or month=6 or month=9 or month=11 then lengthofmonth=30;
 	       if month=2 then lengthofmonth=28;
 	       do day=1 to lengthofmonth;
	          output;
	       end;
	    end;
	  end;
     run;
This is terribly tedious - not to mention fraught with the danger that you'll make errors in leap years. The alternative is to use SAS' intnx function, which increments dates by specified intervals.
     data dates;
         date='01Jan1961'd;
	 do while(date<='31Dec1962'd);
	     output;
	     date=intnx('day', date, 1);
	  end;
     run;
The intnx function increments date (its second argument), by 1 unit (the third argument) of 'day' (its first argument). 
The more astute among you will observe that I get the same effect by saying
     data dates;
         date='01Jan1961'd;
	 do while(date<='31Dec1962'd);
	     output;
	     date=date+1;
	  end;
     run;
because dates are treated as numbers in SAS. This is well and good if I want to increment by single days. Suppose instead I want to increment by weekdays. That is, I want the list of all weekdays in 1961 and 1962. An easy way to do this is:
     data dates;
         date='01Jan1961'd;
	 do while(date<='31Dec1962'd);
	     output;
	     date=intnx('weekday', date, 1);
	  end;
     run;
which is a useful construct in working with the DSF file, and horrendously complicated to do any other way. 
The intnx function, as already said, increments dates, but it does so in a nonintuitive way. Suppose you are incrementing by year.
     date=intnx('year', date, 1);
   Intnx moves the date to the first day of the subsequent year, not forward by one twelve-month period. If you say 'month' instead of 'year', intnx moves the date forward to the first day of the next month however many times you specify. Saying
     date=intnx('month', date, 0);
moves the date to the beginning of the month - the first of the month- in which date falls. Similarly for 'qtr'.
I commonly use the intnx function to do the following:
      date=intnx('month', date, 1)-1;
      date=intnx('qtr', date, 1)-1;
      date=intnx('year', date, 1)-1;
      date=intnx('month', date, 0);
      date=intnx('qtr', date, 0);
      date=intnx('year', date, 0);
      date=intnx('month', date, 0)-1;
      date=intnx('month', date+1, 1)-1;
    Observe here that I have to say date+1. Since the date is currently of the form 31Jan1999, saying 
    
      date=intnx('month', date, 1)-1;
    will leave us with 01Feb1999-1, or 31Jan1999.
      date=intnx('month', date, -11)-1;
      date=intnx('month', date+1, 12)-1;
      data beg_end;
         beginning_date='31Jan1996'd;
         ending_date='31Dec2007'd;
      run;
      data all_dates;
         set beg_end;
	 date= beginning_date;
	 date=intnx('month', date, 1)-1;
	 do while(date<=ending_date);
	    output;
	    date=intnx('month', date+1, 1)-1;
	 end;
      run;
    The first 
    
	 date=intnx('month', date, 1)-1;
    statement is to ensure that the first date is an end-of-month. 
      data beg_end;
         beginning_date='31Jan1996'd;
         ending_date='31Dec2007'd;
      run;
      data all_dates;
          format date date9.;
          set beg_end;
          date=beginning_date;
          if weekday(date)>4 then date=intnx('week', date, 1)+3;
          else date=intnx('week', date, 0)+3;
          do while(date<=ending_date);
              output;
              date=intnx('week', date, 1)+3;
              end;
      run;
      
The weekday() function returns the day of the week, 1 being Sunday. I make the first date a Wednesday (weekday=4) with 
      
          if weekday(date)>4 then date=intnx('week', date, 1)+3;
          else date=intnx('week', date, 0)+3;
      
The logic is simple. If the current date is ``more'' than a Wednesday (ie, weekday(date)>4), then the first admissible date is Wednesday of next week. Sunday of next week is 
      
       date=intnx('week', date, 1);
      
Add 3 to that to get to Wednesday. If the current date is ``less than or equal to'' Wednesday, then go to the beginning of this week
      
       date=intnx('week', date, 0);
      
and add 3 to that.
The rest of the scheme is obvious. This is useful in constructing weekly returns (Thursday-to-Wednesday to avoid any weekend effect).
 
 
 
 
