10-25-2015 07:22 AM
I got the below code from someone else. It is supposed to account for leap year. So during a
1) leap year: 183<=A<366
2) non-leap year: 183<= A<365
183<= A < 365+(4*INT(&Year/4)=&Year)
Can someone explain to me what this does -- (4*INT(&Year/4)=&Year)?
As far as I know INT truncates a number to its integer.
10-25-2015 08:14 AM
Instead of writing code (or using somebody else's code) to determine time intervals, you use the built-in SAS functions, which already account for leap years and for un-equal number of days in a month, and all other quirks of the modern calendar.
The functions are INTNX and INTCK, look them up, use them.
10-25-2015 09:26 AM - edited 10-25-2015 09:28 AM
Here is a simple check that might be easy to understand. Good luck to you...!!!
Data check_year; do year_value = 2000 to 2016; length leap $3; leap='no'; If mod(year_value,4)=0 then leap='YES'; If mod(year_value,100)=0 and mod(year_value,400) ne 0 then leap='NO'; output; end; Run; proc print noobs; var year_value leap; run;
Here is the result of the code for your reference:
year_value leap 2000 YES 2001 no 2002 no 2003 no 2004 YES 2005 no 2006 no 2007 no 2008 YES 2009 no 2010 no 2011 no 2012 YES 2013 no 2014 no 2015 no 2016 YES
Here is some more literature from where I got the calc....
10-25-2015 09:58 AM
You probably do not want to use this trick. First it does not take into account the rules for centuries. Years that are divisible by 100 but not divisible by 400 are NOT leap years. You can probably figure out a way to use the built in date manipulation functions to do what you want. For example to find the number of days in a year you could do:
%let days_in_year = %sysevalf("01JAN%eval(&year+1)"d - "01JAN&YEAR"d) ;
But to the specific question of how to interpret the expression:
The function call INT(&YEAR/4) will divide the year value by 4 and keep only the integer part of the result. If you then multiple by 4 you will only get the same number back when the year was exactly divisible by 4. So this will be true when YEAR is a multiple of 4. SAS returns 1 for true and 0 for false when evaluating a logical expression in an equation. You could do the same thing a little clearer using the MOD() function.
But there are other issues with this %LET statement.
First it is generating the SAS code to call the INT() function instead of evaluating the expression itself. For example try this code:
%let year=2015 ; %let year=183<= A < 365+(4*INT(&year/4)=&year) ; %put &year ;
The result is that YEAR contains the expression: 183<= A < 365+(4*INT(2015/4)=2015)
That means that if you use this macro variable in a data step expression the INT() function is re-run each time through the data step.
Second it is probably not good practice to store it back into the same macro varaible that previously just had the digit string for the year.
10-25-2015 01:18 PM
As a macro language statement, this does nothing useful. Macro language evaluates comparisons from left to right. So the first evaluation is:
183 <= A
This is not a reference to a variable named "A", it is just the letter "A". So the comparison will be either true or false depending on your operating system (ASCII vs. EBCDIC). True comparisons return a 1, and false comparisons return a zero. So midway through the comparisons, macro language is looking at:
1 < 365 + (4*INT(&Year/4)=&Year)
This comparison will always be true, and will therefore return a 1. So the result of your original statement should always be assigning &YEAR a value of 1 (possibly adding + (4*INT(&Year/4)=&Year) aftwards ... I'm not able to verify that right now).
I vote for the recommendation to examine INTNX. Properly used in a DATA step, it can return, for example, a SAS date equivalent to the same day of the year, X years in the future.
10-25-2015 04:47 PM
I believe you've missed that the expression doesn't get evaluated on SAS macro level. It's simply populating a macro variable which I assume is then used in a data step where the expression evaluates on SAS Base language level.
10-25-2015 04:51 PM
As @PaigeMiller already wrote: SAS provides a whole set of calendar functions which do all the magic for you. No need to try and code this.
I suggest you ask the person who provided this code what it's supposed to do - and then re-write the intended logic using SAS calendar functions.