SAS 无效“闰年”; 发行日期 yymmdd8

发布于 2024-07-13 18:40:14 字数 291 浏览 5 评论 0原文

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

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

客户希望恢复到 2 月 28 日。是否有快速/有效的方法来做到这一点? 例如,相当于:

IF iserror(date) then date=date-1; ?

如有任何建议,不胜感激!

I am reading in some raw data that has a couple of bad dates. Specifically, someone has keyed in "29th Feb" on a NON leap year. For example:

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

The customer would like this to revert to the 28th Feb. Is there a quick / efficient method of doing this? eg an equivalent of:

IF iserror(date) then date=date-1; ?

Any suggestions gratefully received!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

怪我闹别瞎闹 2024-07-20 18:40:14

我会更加小心地确定日期。 这是一种方法。 嗯。

%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.
*/

I would be a bit more careful fixing dates. here is one way. hth.

%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.
*/
残月升风 2024-07-20 18:40:14

这是来自 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 ***/

可以通过一种或另一种方式将其合并到您的负载中。

Here is a great tip from SCONSIG. link

/******************************************************************/
 /***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 ***/

It is possible to incorporate this into your load in one way or the other.

桃扇骨 2024-07-20 18:40:14

上面答案的稍微修改版本(我认为)。 尽管使用“??”,但它避免了错误消息 在输入函数中。

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;

Slightly modified version (I think) of the answer above. It avoids the error messages though with the "??" in the input function.

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;
感情废物 2024-07-20 18:40:14

这并不漂亮,并且有转换注释,但它可以工作并且不会出错。

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

This isn't pretty and there are conversion notes but it works and doesn't error.

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; 

Output:

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
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文