如何将SAS表中的所有DATETIME变量转换为DATE9

问题描述

我在SAS中有一个表,其中所有代表日期的变量都在DATETIME20中。格式,我想将它们转换为DATE9。格式。假设我的SAS表中有3个datetime变量(date1,date2,date3),我想将它们转换为DATE9。同时保留其原始名称(date1,date2,date3)。我希望代码具有灵活性,例如,如果我更改变量名称-在代码的序言中更改(date1,date2,date3)的名称,则该代码仍然有效,即,我希望代码针对不同的名称工作和这些日期变量的数量。我在SAS中有以下代码

%let dates = ('date1','date2','date3');

data my_table;
set my_table;
    array numvars _NUMERIC_;
    do _t = 1 to dim(numvars);
        if upcase(vname(numvars[_t])) in &dates. then do;
            numvars[_t] = datepart(numvars[_t]);
        end;
    end;
run;

但是,这不会将我的(date1,date2,date3)变量转换为DATE9。但在此转换后,它们仍然是DATETIME变量,其值不正确。我希望能够更改&dates。第一行的宏变量,这样我就不必在该行之后更改代码

解决方法

除了将存储的值从几秒更改为几天(通过使用DATEPART()函数)之外,您还需要更改用于显示值的格式。使宏变量仅保留变量名列表,以便可以在SAS代码中使用。

%let dates = date1 date2 date3 ;

data my_table;
  set my_table;
  array dtvars &dates ;
  do _t = 1 to dim(dtvars);
    dtvars[_t] = datepart(dtvars[_t]);
  end;
  format &dates date9.;
run;

如果要使其更加动态,请使用FMTINFO()函数查找现有的DATETIME变量。 FMTINFO()函数仅需要格式名称,而不需要完整格式规范,因此使用PROC CONTENTS的输出要比字典视图更容易。

%let dsnin=example;
%let dsnout=example_date;

proc contents data=&dsnin noprint out=contents; run;

proc sql noprint;
 select nliteral(name)
   into :varlist separated by ' '
   from contents 
   where fmtinfo(format,'cat')='datetime'
 ;
%let nvars=&sqlobs;
quit;

data &dsnout;
  set &dsnin;
%if &nvars %then %do;
  array _dt &varlist ;
  do over _dt; _dt = datepart(_dt); end;
  format &varlist date9.;
%end;
run;

您甚至可以更改SQL查询,以仅测试已放入DATES宏变量中的特定变量。

   where fmtinfo(format,'cat')='datetime'
     and findw("&dates",name,' ','sit')