SyntaxHighlighter

Friday, May 24, 2013

GetAttrn Macro

SAS macros can be written as functions that return a value. To write a macro as a function, you can only use macro language statements and all macro variables must be local. The %sysfunc() macro function is used extensively to extend what can otherwise be achieved. The line containing the macro value being returned should not include a semicolon.

Extracting attributes such the number of rows (nobs) or columns (nvars) from a SAS data set is a very common request. Those values and many more can be obtained by using the attrn() function but that requires the use of open() and close() functions.

Therefore wrapping the attrn() function inside of a SAS macro function makes a lot of sense. See the below code used to create the GetAttrn() macro function.

%macro getattrn( dsn =, attr = nobs ) ;
  %local dsid retval ;
  %let retval = . ;

  %let dsid = %sysfunc( open( &dsn. ) ) ;
  %if &dsid. %then %do ;
    %let retval = %sysfunc( attrn( &dsid., &attr. ) ) ;
    %let dsid   = %sysfunc( close( &dsid. ) ) ;
  %end ;

  &retval. 
%mend ;

Because macro processor events take place prior to program compilation you can take advantage of this knowledge and assign a dimension to an array within a data step.

data attribs( drop = dsid ) ;
  modified = put( %getattrn( dsn = sashelp.class, attr = modte ), datetime. ) ;
  obs      = %getattrn( dsn = sashelp.class ) ;
  vars     = %getattrn( dsn = sashelp.class, attr = nvars ) ;

  array atype[ %getattrn( dsn = sashelp.class, attr= nvar ) ] $1 ;

  dsid = open( 'sashelp.class' ) ;
  if dsid then do ;
    do _n_ = 1 to dim( atype ) ;
      atype[ _n_ ] = vartype( dsid, _n_ ) ;
    end ;
  end ;
run ; 

Friday, May 17, 2013

Holidays Macro

There are times when you need to account for holidays when performing date calculations. The below holidays macro creates a data set of holidays for the specified year range. It makes adjustments for holidays that fall on a weekend such as Independence Day in 2015 which is adjusted to July 3, 2015.


/**************************************************************************
*     Program: holidays.sas
*      Author: Tom Bellmer
*     Created: 17MAY2013  
*     Purpose: create a list of holidays for the specified years
*       Usage: %holidays( startyear = 2013, stopyear = 2014 )
*       Notes: use with a hash object to determine holiday adjustments
**************************************************************************/

%macro holidays
  ( 
      startyear = 2010
    , stopyear  = 2050
    , outdsn    = work.holidays
    , view      = y
  ) ;

  data &outdsn.  
    %if %lowcase( %substr( &view, 1, 1 ) ) = y %then / view = &outdsn. ;
  ;
    attrib 
      year    length   =   3  label = 'Year'
      date    length   =   4  label = 'Date'        format = date9.
      dayofweek length = $16  label = 'Day of Week'
      holiday length   = $32  label = 'Holiday'
    ;

    array aholidays[ 10, 2 ] $32 _temporary_ 
      ( 
          "NewYear",        "New Year's Day"
        , "MLK",            "Martin L King, Jr. birthday"
        , "USPresidents",   "President's birthdays"
        , "Memorial",       "Memorial Day"
        , "USIndependence", "Independence Day"
        , "Labor",          "Labor Day"
        , "Columbus",       "Columbus Day"
        , "VeteransUSG",    "Veterans Day"
        , "Thanksgiving",   "Thanksgiving Day"
        , "Christmas",      "Christmas"
      ) 
    ;

    do year = &startyear. to &stopyear. ;

      do _n_ = 1 to dim( aholidays, 1 ) ;
        date = holiday( aholidays[ _n_, 1 ], year ) ;
        /* adjust date forward on Sunday or back on Saturday */
        date = intnx( 'day', date
                 , choosen( weekday( date ), 1, 0, 0, 0, 0, 0, -1 ) ) ;
        dayofweek = put( date, downame.-l ) ;
        holiday = aholidays[ _n_, 2 ] ;
        output ;
      end ;

    end ;

  run ;

%mend ;

/* EOF: holidays.sas  */