如何将SAS E日期转换为可读日期

时间:2018-01-25 08:38:32

标签: sql date sas sas-macro proc-sql

您好我在SAS平台工作,我有一个包含30多列的data_set。该数据集中有两个日期列。该数据集中的日期格式为 1.33E12

这是我表中的一小部分

enter image description here

我想创建一个包含少量列的新数据集,然后将其导出到excel文件。

我的代码是

dataset
 othercolumns |  date1   |   date2
      -         1.33E12    2.53E14 

proc sql noprint;
 create table my_data_set as
 select ID, col_1, col_2, date1, date2
 from data_set;
quit;

我想将date1和date2列中的日期值以10feb2017的可读格式作为date9。 SAS日期格式,以便将它们导出到我的Excel文件中。现在有了E power日期我在excel中将#######作为date1和date2列

我已经尝试了

select ID, col_1, col_2, datepaart(date1), datepart(date2)
  

警告:参数无效,得到'。'日期栏中的值

select ID, col_1, col_2, date1 date9., date2 date9.
select ID, col_1, col_2, date1 DATEw., date2 DATEw.
  

错误:语法错误

select ID, col_1, col_2, date1 format=DATE9., date2 format=DATE9.

在我的表格中获得相同的E日期值

select ID, col_1, col_2, put(date1 , date9. ), put(date2 ,  date9.) 
  

错误:日期值超出范围

如何将E日期转换为可读格式到我的表中,以便我可以将其导出到Excel?

这是我的导出代码

ods excel file ="C:\data.xlsx";
ods excel close;

proc export
  data = work.my_data_set
  dbms = xlsx
  outfile = "C:\data.xlsx"
  replace;
quit;

2 个答案:

答案 0 :(得分:1)

data have;
  unix_ts = 253402300799;
  put unix_ts= datetime21.;
  sas_dt = unix_ts + '01JAN1970:0:0'DT ;
  put sas_dt= datetime21.;
run;

proc sql;
  create table want as 
  select
  (
    case
      when unix_ts + '01JAN1970:0:0'DT > '27FEB8000:0:0'DT then unix_ts + '01JAN1970:0:0'DT - 2 * 86400
      when unix_ts + '01JAN1970:0:0'DT > '28FEB4000:0:0'DT then unix_ts + '01JAN1970:0:0'DT - 1 * 86400
      else unix_ts + '01JAN1970:0:0'DT 
    end 
  ) as sas_date format=datetime21.
  from have;
quit;

而不是剪切和粘贴你应该理解案例陈述和01-JAN-1970

的内容。

253402300799

  • Unix时间戳,从01-JAN-1970开始的秒数,代表31-DEC-9999:23:59:59
  • valid_to中包含的可能的哨兵价值,OP不精确地显示为 2.534E14
  • 日期列被假定为Unix时间戳。

253717747199

  • SAS日期时间值'31-DEC-9999:23:59:59'DT是从01-JAN-1960
  • 开始的秒数

时间戳转换

Unix时间戳值是纪元01-JAN-1970:0:0:0
  SAS日期时间值为纪元01-JAN-1960:0:0:0

因此可以假设SAS值比Unix值大10年(以秒为单位)。

简单的方法是将时基差分添加到Unix时间戳以实现SAS日期时间

  • SAS_DT = UNIX_TS + '01JAN1970'DT; *天真转换;

然而,这是不正确的,因为Unix和SAS日历在一些闰年上不一致!

  • 253,402,300,799https://www.epochconverter.com/
  • 31-DEC-9999:23:59:59
  • 253,717,747,199'31-DEC-9999:23:59:59'DT
  • 差异,315,446,400应为SAS '01-JAN-1970:0:0'DT。但差异实际上是'30DEC1969:00:00'DT
  • 因此,将纪元基线差异添加到远离Unix的时间戳将导致SAS日期时间与Unix中的日历点不同。
    • 换句话说,253,402,300,799 + '01-JAN-1970:0:0'DT'02-JAN-10000:0:0'DT - 比预期的Unix哨兵还要早两天
    • 或者,大约8000年后,Unix和SAS的日历会计系统将偏离2天。

日历偏差

Unix calendaring认为4000年是闰年,29-FEB-4000是有效的 SAS日历错误地认为4000是非闰年,'29-FEB-4000'DT无效。

      ly4000 = '29-FEB-4000:0:0'DT;
               -------------------
               77
ERROR: Invalid date/time/datetime constant '29-FEB-4000:0:0'DT.
ERROR 77-185: Invalid number conversion on '29-FEB-4000:0:0'DT.

同样的偏差在8,000年再次发生。

Unix时间戳转换为SAS datetime的损坏最少,需要进行简单的转换,并在时间范围内为每个未对齐的闰日确定减去一天。

答案 1 :(得分:0)

看起来您有两种不同类型的UNIX时间戳,它们计算特定日期和时间的毫秒数或微秒数 - 通常是1970年1月1日00:00:00.000000。如果不确切知道它们是什么类型的时间戳,我只能对如何将它们转换为人类可读日期做出有根据的猜测。以下是一些可能的解释:

data example;
  date1=2.53e14;
  date2=1.33e12;
run;

proc sql;
create table want as 
select 
  intnx('year',datepart(date/1e3),10,'s') format = yymmdd10. as date1a, 
  intnx('year',datepart(date/1e6),10,'s') format = yymmdd10. as date1b, 
  intnx('year',datepart(date2/1e3),10,'s') format = yymmdd10. as date2a,
  intnx('year',datepart(date2/1e6),10,'s') format = yymmdd10. as date2b
from example;
quit;

这里的逻辑是:

  • 除以1000或1000000以转换为秒
  • 将结果解释为SAS日期时间值,计算从1960年1月1日00:00:00
  • 开始的秒数
  • 从日期时间
  • 中提取日期组件
  • 添加10年转换为UNIX纪元

希望其中一个看起来对你好。