Tuesday, March 5, 2013

Date/Time Stamping Report and SAS Server Page Results

One of the most under-appreciated features of the Macro Language is using it to package short/simple snippets of SAS code. Many programmers don't like to over-use macros (their terminology, not mine) arguing that:
  • why write a macro when the code that it generates is just as simple to write directly?
One example is including the date/time in a report (e.g., as a footnote). For example,

footnote "Run at %sysfunc(datetime(),datetime.)";

And in theory, they have a point - this is simple code to write.

My counter argument is that since it is simple to write, it is simple to package as a macro. My rationale for using a macro for this is that I have worked on far too many projects where someone discovers late in the development that, for example, the corporate standard for showing dates and times is different from what has been hard-coded in countably infinite pieces of code.

So at the beginning of any project I grab the generatedAt from my Macro Toolbox and adjust the default parameters for a given client/project based on their preferences. Then, if they change their mind, I only have to make the change in one place - the macro paramaters.

Here is a slighly modified version (my standard Toolbox header comments removed in the interests of brevity for this posting) of the code for my generatedAt ToolBox macro:

%macro generatedAt
      (prefix=Generated at
      ,dateFormat=worddate.
      ,separator=on
      ,timeFormat=timeampm8.
      );


 %if %length(&timeFormat) gt 0 %then
 %let timeFormat = %sysfunc(time(),&timeFormat.);
 %if %length(&dateFormat) gt 0 %then
 %let dateFormat = %sysfunc(date(),&dateFormat.);
 %let timeFormat = &timeFormat;
 %let dateFormat = &dateFormat;
 %if %length(&dateFormat)=0 or %length(&timeFormat)=0
     %then %let separator =;
     %else %let separator=%str( )&separator%str( );

 &prefix &timeFormat&separator&dateFormat

%mend generatedAt;

And here are some samples of the text it generates:
  • All the defaults:
    %put %generatedAt();
    Generated at 3:01 PM on March 4, 2013
  • Just the time:
    %put %generatedAt(dateformat=);
    Generated at 3:01 PM
  • Just the date (note how I also changed the initial text):
    %put %generatedAt(prefix=Generated on,timeformat=);
    Generated on March 4, 2013
  • Different formats:
    %put %generatedAt(timeformat=time.
                     ,dateformat=weekdate.);
    Generated at 15:01 on Monday, March 4, 2013
The code is pretty simple. But there are a few points I want to make about it (and the advantages of packaging it as a macro).
  • It is easy to use, for example, to include the date/time in a footnote (similar to the above example):
    footnote "%generatedAt";
  • I can specify the format for the date part and the time part, providing a lot more flexibility in how the date/time is displayed given how many different date and time formats SAS provides out of the box, along with what can be created using the date and time datatypes supported by the PROC FORMAT PICTURE statement.
  • If I only want a date, I just provide a blank/null value for the timeformat parameter.
  • Likewise, if I only want a time, I just provide a blank/null value for the dateformat parameter.
I use this macro on virtually every project for both reporting code (e.g., using the macro call as the text for a title or footnote statement), or to include the date/time of the generated output of SAS Server Pages.