SASには、SAS日付値とSAS時間値およびSAS日時値という概念があります。
日付値は、1960年1月1日を第0日として、1日ごとに1つずつ増えます。
もちろん、うるう年(特異なうるう年も含む)も正しく処理できます。
次のプログラムで確認をしてみましょう。
1960年より前は、マイナスの値になります。
data test;
input date yymmdd10.;
put date=;
cards;
19500203
19600101
20020324
20080521
20090405
;
run;
/*
date=-3619
date=0
date=15423
date=17673
date=17992
*/
したがって、引き算をすれば2つの日付の間が何日であるかが
わかります。
data test2;
set test;
prev=lag(date);
diff=date-prev;
put date yymmdd8. +3 prev yymmdd8. +3 diff;
run;
/*
50-02-03 . .
60-01-01 50-02-03 3619
02-03-24 60-01-01 15423
08-05-21 02-03-24 2250
09-04-05 08-05-21 319
*/
SAS日付値,SAS時間値,SAS日時値
SASのデータセットには,数値型と文字型の2種類のデータタイプしかありません.そのため,日付データは数値型のデータとして記録され,日付処理を効率的に扱うためのフォーマットや関数などが用意されています.
日付概念には次の3つがあります.
- SAS日付値:1960年1月1日を0として,1日経過毎に1増加する整数値で記録されます.基準日より過去は負の整数になります.
- SAS時間値:0時0分0秒を0として,1秒毎に1増加する数値で記録されます.小数もあり,0.1は0.1秒のことです.負値もあります.
- SAS日時値:1960年1月1日0時0分0秒を0として,1秒毎に1増加する数値で記録されます.小数も負値もあります.SAS時間値でのh時m分s秒と,SAS日時値の1960年1月1日h時m分s秒は,同じ数値で記録されます.
たとえば,2008年5月28日は,17680という整数値で記録されますが,簡単な日付処理であれば,その整数値がいくつであったかを気にすることなく,日付データを扱えるフォーマットや関数などがあります.
フォーマット・インフォーマット
SAS日付値に読み込む元の日付の形式や,SAS日付値を書き出す形式にあわせて,いくつものSAS日付値フォーマットやインフォーマットがあります.SAS時間値やSAS日時値にも,専用のフォーマット,インフォーマットが用意されています.
次の例では,yymmdd形式で書かれた日付データをSAS日付値として読み込み,別な形式で表示しています.
data;
input date date9.;
put date yymmdd10.;
cards;
28may2008
;
/*
2008-05-28
*/
DATEは,ddmmmyy形式の日付を読み込むインフォーマットであり,同じ形式で書き出す同名のフォーマットもあります.yymmdd.は,その名のとおり,yymmdd形式で書き出す同名のフォーマットであり,同じ形式を読み込む同名のインフォーマットもあります.変数dateには数値17680が格納されますが,ここではその値を気にする必要がありません.
詳しくは,SAS日付関連のフォーマット,インフォーマットを参照してください.
定数
日付の定数値を与えたい場合,それを格納される数値で記述するのは,非常にめんどうです.次のように一般の日付の形式で定数を書くことができます.
data;
date="28MAY2008"d; /*SAS日付値定数*/
time="01:17:00"t; /*SAS時間値定数*/
datetime="28MAY2008:01:17:00"dt; /*SAS日時値定数*/
put date= time= datetime=;
put date= date. time= time. datetime= datetime.;
run;
/*
date=17680 time=4620 datetime=1527556620
date=28MAY08 time=1:17:00 datetime=28MAY08:01:17:00
*/
関数
SASには日付や時間に関連する処理を行う幾つかの関数が用意されています.主なものに
- 現在日や現在時刻を取り出す
- 年や月などの日付構成要素の一部を取り出す
- 日付構成要素から,SAS日付値を作る
- 2つの日付の間隔を数えたり,指定間隔分日付をすすめる
などがあります.
data;
today=date();put today date.; /*現在日*/
start=mdy(1,1,2007);put start date.; /*年月日からSAS日付を返す*/
month=intck("month",start,today);put month; /*日付の間隔を数える*/
run;
/*
02JUN08
01JAN07
17
*/
詳しくは,SAS日付関連の関数をみてください.
また,日付特有の関数ではありませんが,日付フォーマットやインフォーマットをput関数やinput関数とともに使うと,フォーマット,インフォーマットの形式にあわせたデータの読み込みや変換ができます.
フォーマット,インフォーマットの種類については,,SAS日付関連のフォーマット,インフォーマットをみて下さい.
data;
date=input("080528",yymmdd.); /*文字列をSAS日付に読み込む*/
dmy=put(date,date.); /**/
put dmy $;
run;
/*
28MAY08
*/
システムオプション
日付処理に関連するシステムオプションには以下のものがあります.
see also システムオプション
- YRARCUTOFF=1920 SAS 日付処理の 100 年単位の基準年を指定します
see also SAS日付関連のフォーマット,インフォーマット
- DATE ログに日付を出力します
- LOCALE= SAS セッションのための標準ロケールを指定します
NLで始まるフォーマットやインフォーマット,関数の返り値の表記言語となります.
see also SAS日付関連のフォーマット,インフォーマット, SAS日付関連の関数
- DATESTYLE= あいまいな日付に対する ANYDATE 入力形式の日付の順序を順序を指定します
see also SAS日付関連のフォーマット,インフォーマット
- DFLANG= 日付フォーマットの出力言語を指定します
EURで始まるフォーマットやインフォーマットの表記言語となります.
see also SAS日付関連のフォーマット,インフォーマット
- STIMER システムパフォーマンス統計量のログ出力を有効にします
proc options option=yearcutoff;run;
/*
YEARCUTOFF=1920 SAS 日付処理の 100 年単位の基準年を指定します
*/
data;
input date yymmdd.;
put date= yymmdd. date= yymmdd10. date;
cards;
180101
190101
200101
210101
;
/*
date=18-01-01 date=2018-01-01 21185
date=19-01-01 date=2019-01-01 21550
date=20-01-01 date=1920-01-01 -14610
date=21-01-01 date=1921-01-01 -14244
*/
proc options option=date;run;
/*
DATE ログに日付を出力します
NODATE ログに日付を出力しません
*/
proc options option=locale;run;
/*
LOCALE=JAPANESE_JAPAN SAS セッションのための標準ロケールを指定します
*/
proc options option=datestyle;run;
/*
DATESTYLE=YMD あいまいな日付に対する ANYDATE 入力形式の日付の順序を
順序を指定します
*/
proc options option=dflang;run;
/*
DFLANG=JAPANESE 日付フォーマットの出力言語を指定します
*/
proc options option=stimer;run;
/*
STIMER システムパフォーマンス統計量のログ出力を有効にします
NOSTIMER システムパフォーマンス統計量のログ出力を無効にします
*/
その他のよくある方法
sas日付値を使わないで,SASデータセットに日付情報を記録する場合,よく使われる方法には,
- 数値変数に,yymmddの6桁の数値,または,yyyymmddの8桁の数値で格納する.
- 文字変数に,yymmddの6桁の数文字列,または,yyyymmddの8桁の数文字列で格納する.
- 文字変数に,dd/mmm/yyyyなどの英語表記のまま格納する
などがあります.
もっとも,時間を使った計算を行ったり,分類したりする場合は,SAS日付値のほうが扱いやすいので,SAS日付値に変換する必要がでてきます.
SAS日付値に変換するには,
- yymmddの6桁ないし,8桁の数値であれば,MDY関数で,sasdate=mdy(int(mod(date,100)/100),mod(date,100),int(date/10000))
- yymmddの6桁ないし,8桁の文字であれば,INPUT関数で,sasdate=input(date,yymmdd8.)
- 英語表記であれば,INPUT関数で,sasdate=input(date,anydtdte.)
see also SAS日付関連のフォーマット,インフォーマット, SAS日付関連の関数
(Tip)yyyymmddの数値であれば,事前処理をしないで,簡単なフォーマット分類をする方法を紹介しておきます.指数表記フォーマット(E)を用います.
data;
input date;
cards;
20080102
20080104
20080112
20080205
20080212
;
proc freq;tables date;
format date e12.;
run;
/* 累積 累積
date 度数 パーセント 度数 パーセント
----------------------------------------------------------------
2.00801E+07 3 60.00 3 60.00
2.00802E+07 2 40.00 5 100.00
*/
日付関連のプロシジャ
外部システムとの互換性
unixタイムとsas日時値との変換
unixタイムは、1970年1月1日0時0分0秒からの累積秒数で日時を表しているのに対し、
sas日時値(ほかにもsas日付値とsas時間値が別にあることの注意)では、1960年1月1日0時0分0秒からの累積秒数で日時を表している。
よって、この10年分の秒数(315,619,200秒)を足し引きすれば、互いに変換することができる。
sasdatetime = unixdatetime + 315619200; unixdatetime= sasdatetime - 315619200;
data _null_;
unix0='01jan1970:00:00:00am'dt;
sas0='01jan1960:00:00:00am'dt;
d=unix0-sas0;
put d;
run;
/*
315619200
*/
Excel日付とsas日付値との変換
Excelとの日付データのやりとりにおいては,CSV経由にせよ,直接xls形式にアクセスするにせよ,日付値はExcelの内部値に関わらず,自動的に同じ日付に変換されます.(Excelは,日付を内部コードではなく日付表記文字でCSVファイルを出力します).ただし,セルの表示形式を日付でないものにするなどすると,Excel日付の内部コード値は,SAS日付とは体系が違うので,値を変換してやる必要がでてきます.
Excelの日付の内部コード体系には,次の2つがあります.
- 1900/1/1を1として,累積日数で表す.(Win式)
- 1904/1/1を0として,累積日数で表す.(Mac式)
WindowsでExcelを使っている場合は通常前者,Macなら通常後者ですが,オプションで変えることができるので,Excelのメニュー > ツール > オプション > 計算方法 > 1904から計算する で確認してください.
SAS日付値は,1960年1月1日が0でしたから,Win式の場合約60年,Mac式の場合約56年を加えれば,Excel日付の内部値をSAS日付値に変換できます.
sasdate = XlsWinDate + 21915; sasdate = XlsMacDate + 20454;