以下的内容,要感谢 webgu 在人大论坛上的亲情奉献。
在SAS处理中,特别是在多个数据集合并过程中,我们经常要遇到 日期格式不匹配的情况,但是 日期 又是一个非常关键的
匹配关键词,所以有必要 将各种不同的 日期变量的 转化 方法在这里做一个总结,不周到之处请广大博友提出修改意见。
1.
input: 年月日 output: 年月 ,这里要区分 显示 和 实际值 的区别。
输入的时候,有时是数值型,我们可能要将其 转化为字符型,然后再定义其 日期的显示格式;
比较常用的命令:
数值格式转化为字符型: put(year(date),z4.0) ||'-'||
put(month(date),z2.0);
字符格式转化为日期型:input(date,yymmdd10.)
时间变量的截取函数:
conn='01feb2011:8:45'dt;
dat_date=datepart(conn);
format dat_date date9.;
dat_time=timepart(conn);
format dat_time time5.;
Formats:
DATEw. date9. 01JAN2014
DDMMYYw.
YYMMDDw. YYMMDD10. 2014-06-18
YYMMxw.
YYMONw. put x yymon7.;
2012JAN
Functions:
DAY
MONTH
MDY date=mdy(1,2,2001);
2001-01-02
YEAR
季度:QTR(DATE)
今天日期返回函数:TODAY()
data test;
input time yymmn6.;
date=time-1;
format date yymmd7. time yymmd7.;
cards;
201201
201202
201203
201204
201205
;
run;
Data RiskFreeRateByMonth;
SetRiskFreeRateByMonth;
year_month=put(year(date),z4.0) ||'-'||
put(month(date),z2.0);
Proc print data=_last_(obs=25);
Run;
We can also use the “YYMMD.” format to do the same thing
For example:
year_month=put(date,YYMMD.);
data data _null_;
x='7jan2012'd;
put x
yymm7.;
put x
yymmc7.;
put x
yymmd7.;
put x
yymmn6.;
put x
yymmp7.;
put x
yymms7.;
put x
yymon7.;
run;
2012M01
2012:01
2012-01
201201
2012.01
2012/01
2012JAN
data a;
format date yymmdd10.;
date=mdy(1,2,2012);
yymm=compress(year(date)||month(date));
time=input(yymm,yymmn6.);
date1=time-1;
format date1 yymmd7.;
format time
yymmn6.;
run;
data a;
format date yymmdd10. time yymmd7. date1
yymmd7.;
date=mdy(1,2,2001);
time=input(put(date,yymmn6.),yymmn6.);
date1=time-1;
run;
%let e=3;
data a;
format date yymmdd10. time yymmd7. date1
yymmd7.;
date=mdy(1,2,2001);
time=input(put(date,yymmn6.),yymmn6.);
do i=1 to &e;
date1=intnx('month',time,-i);
output;
end;
run;
时间序列生成年月数据:
DATA zuoye7;
SET dd.cpi;
month=intnx('month','01NOV2009'd,_n_+1) ;
format month monyy7.;
proc print;
title '加入变量Month后的数据集输出';
run;
substr(put(date(),yymmddn8.),1,6)
运行后得到201207, 这个是当月的月份,请问如何得到上月的月份呢,运行后应该得到201206
substr(put(intnx('month',date(),-1),yymmddn8.),1,6)
data b;
set tmp;
mon=substr(put(left(date),7.),6,2);
year=substr(put(left(date),7.),1,4);
day='01';
time=MDY(mon,day,year);
informat time yymmdd10.;
format time yymmdd10.;
drop date mon year day;
rename time=date;
run;
临床试验数据中常包含很多日期数据,而且这些数据往往是年、月、日分开的,即用了三个变量分别存放年、月和日。现在要把它们组合在一起并以常用形式表现出来,以便后续计算和阅读。
假设源数据的年、月、日数据分别存放于三个变量year、month和day中。
第一步: 组合: 把年月日三个数据合并起来存放于变量date中
程序:
data a;
input
year month day;
date
= mdy (month,day,year); datalines;
1921 7 1
1949 10 1
1997 7 1
2006 7 31
2007 6 29
;
run;
注意到mdy()函数是实现这一步的关键。该函数就是为我们转换日期用的。非常好用。
mdy()函数需要三个参数,这三个参数的排列顺序固定,中间用“,”号分隔,即:
月,日,年。这里的月日年即可以是数字,如1997年6月28日就是mdy(6,28,1997),也可以是变量名,如本例。
有的时候,源数据的年月日的类型是文本型的,这也不用怕,用下面的程序解决。
data a;
input
year$ month$ day$;
date
= mdy(input(month,8.),input(day,8.),input(year,8.));
datalines;
1921 7 1
1949 10 1
1997 7 1
2006 7 31
2007 6 29
;
run;
注意到在mdy()函数中又嵌套了一个函数input()。input()函数的用处是把文本型数字转换成数值型数字(呵呵,有点怪是不?但实际工作中经常会碰到)。该函数有两个参数,前面一个是包含被转换数字的变量(名),后面一个是转换后数据的格式(关于格式可多了去了,有兴趣大家自己看吧,本例的格式是最简单的数值型8位)。
第二步: 表现:
将时间日期用常用的表现方式表现出来
在这里我必须要说明,由于时间日期的表现方式实在太多,我们只给大家介绍三个认识一下。
在上一步中,无论源数据中的年月日是文本型的还是数值型的,在新生成的SAS数据集a中都已经被组合到一起并存放到数值型变量date中了。注意这些数据与一般数据无异,但它们是与源数据中的年月日一一对应的。SAS把1960年1月1日作为基准,所有日期与这一基准的差转换成天数存放。如果早于1960年1月1日,差为负数,如果晚于1960年1月1日,差为正数。
我选了三种日期表现形式,用print过程输出,其程序和结果如下:
程序:
data b;
set
a;
date1
= date; date2
= date;
date3
= date;
proc print data=b noobs; format
date1 date9. date2 mmddyy10. date3
yymmdd10.; run;
输出:
SAS
システム 2007年
6月29日 金曜日
08:44 2
year month day date date1 date2 date3
1921 7 1 -14063 01JUL1921 07/01/1921 1921-07-01
1949 10 1 -3744 01OCT1949 10/01/1949 1949-10-01
1997 7 1 13696 01JUL1997 07/01/1997 1997-07-01
2006 7 31 17013 31JUL2006 07/31/2006 2006-07-31
2007 6 29 17346 29JUN2007 06/29/2007 2007-06-29
注意date变量值虽然与一般数字无异,但与同一记录中的年月日是一一对应的。后面date1到date3是同一日期的三种表现形式,其中有我们中国人习惯的年月日形式。
如果数据是用两位数来表示年份的需要设置前两位属于那个世纪
eg:08/14/83
需要通过设置世纪来让SAS知道是1983或者是1783或者2083
SAS默认的是两位数日期在1920到2019 之间
即当两位数年份用20-99时SAS认为是1920-1999年
当两位数年份是00-19时SAS认为是2000-2019年
要改变默认设置可以通过OPTINS进行 在SAS中输入
OPTIONS yearcutoff=1950;
即可把SAS默认的两位数日期改为1950-2049年之间
OPTIONS yearcutoff=1700
把SAS默认的两位数日期改为1700-1799年之间
(4)SAS的日期值之间可以进行加减运算从而可以方便的求出两个日期之间间隔多少天
futherdate=checkdate+21
可以求出checkdate21天后的日期是什么
(5)日期函数
day()、month()、qrt()、year()、weekday()可以分别从SAS日期值返回日
、月、季、年、和星期
mdy(m,d,y)可以求出SAS日期值
yrdif(stardate,enddate,'actual')可以返回两个日期之间的真实间隔天数
在sas中用sql过程的时候,如何把数字转为日期?
如:想查2004年4月1日到20111年4月的数据.
proc sql;
create table index.volindex as
select date, vix,vxo,vxn,vxd from index.cboe_vol_index
where date between ‘01apr2004’d
and ‘30apr2011’d;
quit;
如果原数据中date是字符型
where substr(date,1,8) between '20040401'
and '20110430';
2. 数值型 转化为
日期型:
我的问题是原始的数据库里有一个Date变量,为11.的数值型,形如20120304
我想把它变为日期型,如yymmdd10.,形如2012-03-04
?
data new;
input date 11.;
date_1=mdy(mod(int(date/100),100),mod(date,100),int(date/10000));
format date_1 yymmdd10.;
put date_1 yymmdd10.;
datalines;
20010101
20020305
;
run;
或者:
data new;
input date 11.;
date_1=input(put(date,z8.),yymmdd10.);
format date_1 yymmdd10. ;
datalines;
20010101
20020305
;
run;
如何将形如20010101,20020305这样的数值型变量转换成日期型变量呢?
data x;
input k;
cards;
19840123
;
run;
data y;
set x;
a=compress(trim(k));
length z1 $10.;
z1=compress(substr(a,1,4)||'-'||substr(a,5,2)||'-'||substr(a,7,2));
z2=mdy(substr(a,5,2),substr(a,7,2),substr(a,1,4));
format z2 yymmdd10.;
run;
data new;
input date yymmdd8.;
format date date9.;
datalines;
20010101
20020305
;
proc print;run
;
data test;
input num;
date = input(put(num, 8.), YYMMDD8.);
format date
YYMMDD10.;
cards;
20010101
20020305
19970701
;
proc print;
run;
3.日期型转化为数值型:
SAS中的日期数据转化为数值型
SAS中的日期数据比如,2004-04-15,转换为数值型的20040415?
date=compress(date,'-');
date1=input(date,yymmdd10.);
informat date1 yymmdd10.;
format date1 yymmdd10.;
drop date;
rename date1=date;
label date1='date';
%macro
yourdays(birthday=);
ods listing close;
ods html;
data _null_;
file print;
time=time();
y=today();
x=&birthday;
year=Intck('year',x,y);
qtr=Intck('qtr',x,y);
month=Intck('month',x,y);
week=Intck('week',x,y);
day=Intck('day',x,y);
put 100*'*';
put "现在是"y:yymmdd10."号"
time:time5."分。";
put;
put
"截止到目前,你在这个世界上活了"year"年,"
month"个月,"qtr"季度," week"个星期," day"天。";
put;
put "请珍惜你生命中的每一天!";
put;
put 100*'*';
run;
ods html close;
ods listing;
%mend;
%yourdays(birthday='08jun1988'd);
data a;
* format b time8.;
a='09:00';
b=input(a,time5.);
b=hms(scan(a,1,':'),scan(a,2,':'),'00');
put a= b= b=
time8.;
run;
data work.a;
input x$;
cards;
,9:00
,10:00
,12:30
;
run;
data work.a;
set work.a;
b=hms(scan(compress(x,","),1,":"),scan(compress(x,","),2,":"),"00");
format b time8.;
run;
data a;
format b time8.;
aa=',09:00';
a=substr(aa,2);
b=hms(scan(a,1,':'),scan(a,2,':'),'00');
run;
scan('string',i,'char')
char是分隔符,i是取第几部分
较长的时间变量转换
------------------------------------------------
data a;
input time$ 1-20;
cards;
2003-12-1 9:23:24
2003-2-3 14:12:09
2003-12-10 9:36:24
;
run;
data
b;
set
a;
dtime=input(time, anydtdtm21.);
format
dtime datetime20.;
run;
proc print data=b;
run;
------------------------------------------------
DATA A;
INPUT TIME $20.;
CARDS;
2013/7/1 21:29
2013/7/1 21:29
2013/7/1 21:29
2013/7/1 21:29
2013/7/1 21:30
2013/7/1 21:32
2013/7/1 21:32
2013/7/1 21:32
2013/7/1 21:34
2013/7/1 21:34
2013/7/1 21:35
2013/7/1 21:35
2013/7/1 21:36
2013/7/1 21:37
2013/7/1 21:37
2013/7/1 21:37
2013/7/1 21:37
2013/7/1 21:38
;
RUN;
PROC SORT;
BY TIME;
DATA A;
SET A;
BY TIME;
IF LAST.TIME;
LAG_T=LAG(TIME);
IF LAG_T='' THEN LAG_T=TIME;
A1=SUM(INPUT(SCAN(TIME,1,' '),ANYDTDTM.),INPUT(SCAN(TIME,2,'
'),ANYDTDTM.));
A2=SUM(INPUT(SCAN(LAG_T,1,' '),ANYDTDTM.),INPUT(SCAN(LAG_T,2,'
'),ANYDTDTM.));
DIF_T=INTCK('MINUTE',A2,A1);
DROP A: LAG_T;
RUN;
PROC PRINT;
RUN;
较长的时间变量用的很少,看起来也比较别扭,这里仅仅提一下,具体的应用参考官方的函数手册。
data tmp;
input QTime datetime19.;
tdif_in_s=dif(QTime);
tdif_in_m= tdif_in_s/60;
format QTime datetime.;
cards;
04JAN2005:09:25:04
04JAN2005:09:30:08
04JAN2005:09:30:32
04JAN2005:09:30:48
04JAN2005:09:30:56
04JAN2005:09:31:12
04JAN2005:09:31:20
04JAN2005:09:31:28
04JAN2005:09:31:36
04JAN2005:09:31:44
04JAN2005:09:31:52
04JAN2005:09:32:24
04JAN2005:09:32:40
04JAN2005:09:33:04
04JAN2005:09:33:12
04JAN2005:09:33:20
04JAN2005:09:33:28
04JAN2005:09:33:36
04JAN2005:09:33:44
04JAN2005:09:33:52
04JAN2005:09:34:00
;
proc print;run;
data out;
set raw;
lag1=lag(qtime);
inter=intck('minute',lag1,qtime);
if inter>30;
run;
是不分ID做更好?
说明:在我们使用INTCK函数时候,我们求解的是间隔的年、月、天、小时、分、秒等数值,在分钟求解中,前后两个数值
可能并没有达到1分钟,但是intck函数 也会返回 1分钟的数值,只要两个数值 在 分钟 刻度上有了递增,这个函数 就会返回
1,如果在 分钟 位置上 没有递增,即便 时间 增加数 大于 跨分钟 数的 两个时间 的比较,也只会返回
0,参见一下的例子。
data tmp;
input QTime datetime19.;
tdif_in_s=dif(QTime);
tdif_in_m= tdif_in_s/60;
jj=int(tdif_in_m);
lag1=lag(qtime);
inter=intck('minute',lag1,qtime);
format lag1 datetime19.; informat lag1
datetime19.;
format QTime datetime19.; informat QTime
datetime19.;
cards;
04JAN2005:09:25:04
04JAN2005:09:30:08
04JAN2005:09:30:32
04JAN2005:09:30:48
04JAN2005:09:30:56
04JAN2005:09:31:12
04JAN2005:09:31:20
04JAN2005:09:31:28
04JAN2005:09:31:36
04JAN2005:09:31:44
04JAN2005:09:31:52
04JAN2005:09:32:24
04JAN2005:09:32:40
04JAN2005:09:33:04
04JAN2005:09:33:12
04JAN2005:09:33:20
04JAN2005:09:33:28
04JAN2005:09:33:36
04JAN2005:09:33:44
04JAN2005:09:33:52
04JAN2005:09:34:00
;
proc print;run;
------------------------------------------------
------------------------------------------------
------------------------------------------------
------------------------------------------------
------------------------------------------------
附
录:
常用函数:
(一)字符转换:
1)字符型转换成数值型
Numvar=INPUT(source,informat)
2)数值型转换成字符型
Chavar=PUT(source,format)
(二)字符型变量的处理
1)提取字符串
substr('string',start,length)
scan('string',i,'char')
char是分隔符,i是取第几部分
2)替换字符串
translate('string','to_string',‘from_string’)
upcase()得到字符串大写
low()得到字符串小写
3)字符串长度
length()从最右边非空格到最左边,包括空格
4)查找字符串的函数
find(string,,substring)
返回的是子字符串在字符串中首次出现的位置,<>中表示可以省略,其中startpos表示开始查找的位置
5)删除字符变量中的部分内容
compress('string','char','modifier')
char是要删掉的内容,modifier若为d,则去除字符串中数字,a则去除字母
6)去除字符型变量中的空格
trim()去除尾部空格,left()将字符串首部空格移到尾部,strip()去除首尾两部的字符
7)合并字符串变量
!! || cat()
(三)数值型变量的处理
round(argumet,)按照四舍五入保留到round-off-unit位
ceil,floor分别向上和向下取整数,INT取整数部分。
(四)日期函数
year(date)/month(date)/weekday(date) 一周内的第几天/mdy(month,day,year)
SAS日期值
例如date=20120123,存储的是距离1960.1.1的日期值,date_year=int(date/10000),将其当做数据型处理