SAS无效的“闰年”日期问题 yymmdd8

4

我正在读取一些原始数据,其中有几个错误的日期。具体来说,在非闰年中,某人输入了“2月29日”。例如:

data _null_;
input test :yymmdd8.;
format test date9.;
cards;
20270229
run;

客户希望将日期回滚到2月28日。有没有快速/高效的方法可以做到这一点?例如等价于:IF iserror(date) then date=date-1;?任何建议都将不胜感激!
4个回答

4

我会更加谨慎地修复日期。以下是一种方式,希望有所帮助。

%put sysvlong=&sysvlong sysscpl=&sysscpl;           
/* sysvlong=9.02.01M0P020508 sysscpl=W32_VSPRO */

/* read a date both as character(temp) and numeric(date).
   if the numeric date is missing then check if the
   character date ends with "0229," if so, then change it
   to "0228" and see if it is a valid date. 
   If OK, then that is it. otherwise, keep it missing. */
%let FEB29 = 0229; 
%let FEB28 = 0228;
data one;
  drop temp;
  input temp $char8. @1 date ?? yymmdd8.;
  if missing(date) then link fix;
  format date b8601da.;
  put (_all_) (=);
  return;
fix:
  if length(strip(temp))^=8 then return;
  if substr(temp,5) ^= "&FEB29" then return;
  date = input(cat(substr(temp,1,4), "&FEB28"), ?? yymmdd8.);
return;
cards;
20080229  ok
20090229  should be changed to 28th
201XX229  this should be missing
20110229  -> 28
20120229  ok 
20130229  -> 28
20270229  -> 28
;
run;

/* on log
temp=20080229 date=20080229
temp=20090229 date=20090228
temp=201XX229 date=.
temp=20110229 date=20110228
temp=20120229 date=20120229
temp=20130229 date=20130228
temp=20270229 date=20270228
NOTE: The data set WORK.ONE has 7 observations and 1 variables.
*/

3

这里有来自SCONSIG的一条非常好的技巧。 链接

/******************************************************************/
 /***TIP00039.SAS                                                ***/
 /***   Leap Year Problem                                        ***/
 /***                                                            ***/
 /***   Most of us know that if the year is divisible by 4 then  ***/
 /***   that year is a Leap Year.  However, if the year is a     ***/
 /***   century year and is NOT divisible by 400 then that       ***/
 /***   century year is NOT A LEAP YEAR.                         ***/
 /***   (ie, 1700, 1800, 1900, 2100, 2200, 2300 are not LEAP     ***/
 /***        YEARS)                                              ***/
 /***                                                            ***/
 /******************************************************************/

 data leapyear;
   do year = 1600 to 2400 by 100;
    date = mdy(02,29,year);        /*** Leap Date                       ***/
    if date = . then do;           /*** If FEB 29th but not a Leap Year ***/
       date = mdy(03,01,year) - 1; /*** Make date March 1st and then    ***/
    end;                           /***   subtract 1 day                ***/
    output;
   end;
   format date mmddyy10.;
 run;

 proc print; run;

 /*** end of sas program - TIP00039 ***/

可以以某种方式将其整合到您的负载中。


感谢AFHood - 目前我正在尝试不同的方法(已发布了一个新问题),但如果我无法消除导致错误消息的问题,我认为我将使用这个方法(将年份放入宏变量中)。很棒的代码!谢谢。 - Allan Bowe

1
稍微修改了上面的答案(我想)。它避免了在输入函数中使用“??”时出现的错误消息。
data testit;
   format indate yymmdd10.;
   input x $8.;

   indate = input(x, ?? yymmdd8.);
   if indate=. then indate= input(put(x - 1, 8.), ?? yymmdd8.);


    put indate=;

cards;
20080229
20090229
20100229
20110229
20120229
20130229
20270229
run;

1
喜欢使用 ?? 修饰符! - Allan Bowe

0

这不是很漂亮,有一些转换注释,但它能够正常工作而且没有错误。

data testit;
   format test2 yymmdd10.;
   input x $8.;
   mod4 = mod(mod((substr(x,1,4)/4),4) * 10,10);   
   if mod4 NE 0 then x = x - 1;
   test2=input(x,yymmdd8.);
   put x= test2=;

cards;
20080229
20090229
20100229
20110229
20120229
20130229
20270229
run; 

输出:

x=20080229 test2=2008-02-29
x=20090228 test2=2009-02-28
x=20100228 test2=2010-02-28
x=20110228 test2=2011-02-28
x=20120229 test2=2012-02-29
x=20130228 test2=2013-02-28
x=20270228 test2=2027-02-28

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接