SAS9

Managing Date Loops in Macros

Simon 12 Aufrufe

A classic challenge for any SAS© programmer is to transform a simple Data Step loop into a dynamic Macro. The date + 7 days operation suddenly becomes complex.

Why does copy-pasting fail? And how do you handle time in the macro processor? Here are the explanations from the discussion.

1. The Problem: Literal vs. Text

In a Data Step, SAS© intelligently interprets dates. When you write i = '01Oct2007'd;, SAS© immediately converts this literal into a number (the number of days since 1960). The i + 7 operation is therefore a simple mathematical addition.

In a Macro, everything is a STRING. The user tried this:

1%let i = '01Oct2007'd;
2/* &i contient le texte "'01Oct2007'd" */
3%let i = %eval(&i + 7);
4/* ERREUR ! */
The %eval function (macro integer calculator) sees the text '01Oct2007'd + 7. It doesn't know how to convert the '...'d literal into a number. It therefore fails to perform the addition.

2. The Solution: Using the Numeric Value (%SYSFUNC)

As Linda (LAP) explains, to do math in a macro, you must work with pure numbers, not formatted dates.

You need to use %sysfunc() to access SAS©'s conversion functions.

The correct approach:

  1. Convert the text date into a SAS© number from the start.

  2. Calculate (loop, increment) on this number.

  3. Re-format the number into a readable date only for final display/use.

The Corrected Code

Here's how to transform the user's logic into a functional macro:

1%macro loop;
2 /* 1. On convertit le littéral en nombre (ex: 17440) grâce à PUTN ou INPUTN */
3 /* Note: Ici on utilise l'astuce de formater le littéral en nombre brut '8.' */
4 %let i = %sysfunc(putn('01Oct2007'd, 8.));
5
6 /* On convertit aussi la borne de fin */
7 %let fin = %sysfunc(putn('31Dec2007'd, 8.));
8 
9 /* 2. La boucle compare maintenant deux nombres entiers */
10 %DO %until (&i >= &fin);
11
12 /* 3. L'incrémentation fonctionne car &i est un entier */
13 %let i = %eval(&i + 7);
14
15 /* 4. Pour l'affichage, on re-transforme le nombre en date lisible */
16 %put %sysfunc(putn(&i, date9.));
17
18 %END;
19%mend loop;
20 
21%loop;

3. The Alternative: %SYSEVALF

The expert Peter_C mentions a more powerful function: %sysevalf. Unlike %eval (which only handles integers), %sysevalf (System Evaluation Floating) handles floating-point numbers, but is also able to better interpret certain date literals if they are in double quotes.

However, the most robust method remains explicit conversion to a number via %sysfunc.

ContextDate HandlingExample
Data StepAutomatic (literals 'ddMMMyyyy'd)date + 1;
MacroManual (everything is text)%eval(%sysfunc(inputn(&date,date9.)) + 1);

Golden Rule: The macro processor is "blind" to data types. If you want to do math, give it pure numbers. If you want dates, convert them to numbers before passing them to it.