BookmarkSubscribeRSS Feed
Patrick
Opal | Level 21

I would have expected that when running below code....

data sample;
  input id $ dob:date9.;
  format dob curr_date date9.;
  do curr_date='27Feb2020'd,'28Feb2020'd,'29Feb2020'd;
    age=floor(yrdif(dob,curr_date,'age'));
    output;
  end;
  datalines;
A9991 28Feb2004
A9992 29Feb2004
;

proc print data=sample;
run;

...obs 5 would return an age of 15.

Patrick_1-1673065212499.png

I've done some Internet searching but couldn't really find a good explanation why it's 16. 

Is that a "bug" in the function or is there some logical explanation/convention why the age becomes already 16 on Feb28?

 

 

 

7 REPLIES 7
mkeintz
PROC Star

I would have the same expectation as you when using the 'AGE' basis (i.e.  DOB=29FEB2004 would have an age of 15 on 28feb2020). I'd be very interested to learn of a justification for a result of 16.

 

But you can get 15 for that situation when using the "ACT/ACT" basis:

 

data sample;
  input id $ dob:date9.;
  format dob curr_date date9.;
  do curr_date='27Feb2020'd,'28Feb2020'd,'29Feb2020'd;
    age=floor(yrdif(dob,curr_date,'act/act'));
    output;
  end;
  datalines;
A9991 28Feb2004
A9992 29Feb2004
;

proc print data=sample;
run;

 


Obs id dob curr_date age
1 A9991 28FEB2004 27FEB2020 15
2 A9991 28FEB2004 28FEB2020 16
3 A9991 28FEB2004 29FEB2020 16
4 A9992 29FEB2004 27FEB2020 15
5 A9992 29FEB2004 28FEB2020 15
6 A9992 29FEB2004 29FEB2020 16

 

 

 

 

--------------------------
The hash OUTPUT method will overwrite a SAS data set, but not append. That can be costly. Consider voting for Add a HASH object method which would append a hash object to an existing SAS data set

Would enabling PROC SORT to simultaneously output multiple datasets be useful? Then vote for
Allow PROC SORT to output multiple datasets

--------------------------
Patrick
Opal | Level 21

@Kurt_Bremser wrote:

This is convention. People born on a 29th of February celebrate their birthday on the 28th in non-leap years; law also respects this.


My sample code is for a leap year for someone born in a leap year - and that's why I'm wondering why the age already increases on Feb 28 and not only on Feb 29.

Kurt_Bremser
Super User

Overlooked that.

I see two explanations:

  • it's an artifact of the underlying calculation
  • there is some legalese in the US which considers all people born on a 29th to have been born on the 28th, regardless of year
mkeintz
PROC Star

@Kurt_Bremser wrote:

Overlooked that.

I see two explanations:

  • it's an artifact of the underlying calculation
  • there is some legalese in the US which considers all people born on a 29th to have been born on the 28th, regardless of year

I'd be disappointed if it is really a calculation artifact.  I hope it's actually due to some technical/legal instruction on age determination for people born on the 29th of February.  Otherwise, the 'age' method for YRDIF is inexplicably at odds with the "continuous" method for INTCK.  For instance, try using 

 

age=intck('year',dob,curr_date,'continuous');

 

which reproduces the intuitively expected results using the "ACT/ACT" basismethod in YRDIF.

 

@Patrick - maybe it's worth asking SAS support to find out what reference SAS used in constructing YRDIF with method=age.

 

 

Edited addition:  Of course, if the YRDIF use of the "age" basis does actually adhere to some legalistic definition of age for births on Feb 29, then that would mean using the "continuous" method for INTCK (that I've been using for years) to calculate age is wrong.

--------------------------
The hash OUTPUT method will overwrite a SAS data set, but not append. That can be costly. Consider voting for Add a HASH object method which would append a hash object to an existing SAS data set

Would enabling PROC SORT to simultaneously output multiple datasets be useful? Then vote for
Allow PROC SORT to output multiple datasets

--------------------------
ErikLund_Jensen
Rhodochrosite | Level 12

hi @Patrick 

 

This is a very interesting discussion, because there seems to be a lot of confusion about leapling's birthday, There are diffrerent conflicting rules, or no rules at all.

 

There is a lot of stuff on www on this. A search on situations where it really matters to people, like "born on february 29 when do you celebrate your birthday" or "born on february 29 when can you legally drink" gives a lot of answers, some of which seems highly competent, but they only add to the confusion. It seems that a leapling cannot drink before march 1 in the year she turns 21, but her driver's licence expires on February 28. I recommend this: https://bgwlawyers.com/leaping-through-time-the-leap-year-enigma/

 

I had the problem with a SAS function that returns age from birthday. In a municipal administration different departments seems to have different rules for determining age, so a leapling can get into a public kindergarten from february 1, but cannot vote in an election held on february 28. 

 

It is a mess, and it can have severe consequences in some cases, e.g. applying for citizenship before a given age. I have even heard of a case here in Denmark where a person was denied a test for a driver's licence because the police found that she was only 4 years old, as her birthday on february 29 had only reoccurred 4 times since her birth. 

 

But one cannot really blame SAS for not implementing consistent rules in different functions when there are no consistent rules to implement, and there are so many date functions that you can always choose one that returns the right answer for your specific purpose.

 

If you are making this computation for yourself, you can lay down your own rules, but if you are preparing data to end users, I can only suggest that you ask them to decide which day they prefer. They might find it hard to come up with an authoritative answer, but then it's not your problem any more.

 

 

 

 

yabwon
Onyx | Level 15

Hi,

 

I did some experiments, try and errors, and it looks like yrdif() function with 'age' works like this:

options ls=max;

proc fcmp outlib=work.f.p;
  function leap(year);
    return (
      (mod(year,4)=0 and mod(year, 100)^=0) or mod(year,400)=0
    );
  endsub;
run;

options cmplib=work.f nosource;

data test;
  length z 8; /*test if "by hand" = yrdif() */

  do dob = '25feb2015'd /*to '4mar2015'd, '25feb2016'd*/ to '4mar2019'd;
    do curr_date = dob /*to '5mar2024'd, '25feb2025'd */ to '5mar2045'd;

      /*- "by-hand approach" -----------------------------------------------------*/
      leaps=0;
      do yy = year(dob) to year(curr_date);
        leaps+leap(yy);
      end;

      dobMD = 100*month(dob)+day(dob);
      cdtMD = 100*month(curr_date)+day(curr_date);

      a=0;
      select;
        when (leap(year(dob)) AND leap(year(curr_date)))
          do; 
            leaps+(-1);
            leaps=max(leaps,0);
            a = ifn(dobMD<229
                    ,ifn(229<=cdtMD,-leaps-1,-leaps  )
                    ,ifn(229<=cdtMD,-leaps  ,-leaps+1)
                   );
          end;
        when ( leap(year(dob))       ) a = ifn(dobMD<=228,-leaps  ,-leaps+1);
        when ( leap(year(curr_date)) ) a = ifn(cdtMD<=228,-leaps+1,-leaps  ); 
        otherwise a=-leaps;
      end;
      x = (curr_date - dob + a) / 365;
      /*-------------------------------------------------------------------------*/


      /* SAS function */
      y = yrdif(dob,curr_date,'age');

      /* comparisons */
      z = (round(x,1e-9)=round(y,1e-9));
      if not Z then output;

    end;
  end;
  format dob curr_date yymmdd10.;
run;

log:

NOTE: The data set WORK.TEST has 0 observations and 10 variables.
NOTE: DATA statement used (Total process time):
      real time           15.11 seconds
      cpu time            15.12 seconds

 

Bart

_______________
Polish SAS Users Group: www.polsug.com and communities.sas.com/polsug

"SAS Packages: the way to share" at SGF2020 Proceedings (the latest version), GitHub Repository, and YouTube Video.
Hands-on-Workshop: "Share your code with SAS Packages"
"My First SAS Package: A How-To" at SGF2021 Proceedings

SAS Ballot Ideas: one: SPF in SAS, two, and three
SAS Documentation



hackathon24-white-horiz.png

The 2025 SAS Hackathon Kicks Off on June 11!

Watch the live Hackathon Kickoff to get all the essential information about the SAS Hackathon—including how to join, how to participate, and expert tips for success.

YouTube LinkedIn

How to Concatenate Values

Learn how use the CAT functions in SAS to join values from multiple variables into a single value.

Find more tutorials on the SAS Users YouTube channel.

SAS Training: Just a Click Away

 Ready to level-up your skills? Choose your own adventure.

Browse our catalog!

Discussion stats
  • 7 replies
  • 1635 views
  • 1 like
  • 5 in conversation