turn on suggestions

Auto-suggest helps you quickly narrow down your search results by suggesting possible matches as you type.

Showing results for

Find a Community

- Home
- /
- SAS Programming
- /
- General Programming
- /
- How do I account for leap year in a formula?

Topic Options

- Subscribe to RSS Feed
- Mark Topic as New
- Mark Topic as Read
- Float this Topic for Current User
- Bookmark
- Subscribe
- Printer Friendly Page

- Mark as New
- Bookmark
- Subscribe
- Subscribe to RSS Feed
- Highlight
- Email to a Friend
- Report Inappropriate Content

10-25-2015 07:22 AM

Hi,

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

%LET Year=

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.

Thank you

- Mark as New
- Bookmark
- Subscribe
- Subscribe to RSS Feed
- Highlight
- Email to a Friend
- Report Inappropriate Content

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.

- Mark as New
- Bookmark
- Subscribe
- Subscribe to RSS Feed
- Highlight
- Email to a Friend
- Report Inappropriate Content

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....

http://support.sas.com/kb/44/233.html

Kannan Deivasigamani

- Mark as New
- Bookmark
- Subscribe
- Subscribe to RSS Feed
- Highlight
- Email to a Friend
- Report Inappropriate Content

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:

`(4*INT(&Year/4)=&Year)`

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.

`(0=MOD(&YEAR,4))`

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.

- Mark as New
- Bookmark
- Subscribe
- Subscribe to RSS Feed
- Highlight
- Email to a Friend
- Report Inappropriate Content

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.

Good luck.

- Mark as New
- Bookmark
- Subscribe
- Subscribe to RSS Feed
- Highlight
- Email to a Friend
- Report Inappropriate Content

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.

- Mark as New
- Bookmark
- Subscribe
- Subscribe to RSS Feed
- Highlight
- Email to a Friend
- Report Inappropriate Content

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.