SAS DATEの問題-“最も近い月の計算”
質問
2つの日付の間の「最も近い」月数に相当する数値を計算する必要があります。ただし、標準のSAS関数(INTCK)は、日付パラメーターのDAYを考慮するように調整されていません(たとえば、1に丸める必要がある場合、以下のコードは0に解決されます)。
この問題を解決する「最も近い」方法は何ですか?
data _null_;
x="01APR08"d;
y="28APR08"d;
z=intck('MONTH',x,y);
put z= ;
run;
編集:Martinsコメントへの応答。
0か月に丸めます-国境は関係ないと思います。複製しようとしている関数(NEAREST_MONTHS)はDCS(Sungard預言者アプリケーション)から来ています。日付の処理方法についてさらに理解するために、アプリケーション自体でいくつかのテストを実行する機会を待っています(ここに結果を投稿します)。
ヘルプファイルには以下が含まれます。 カテゴリー 日付
説明
2つの日付の差を最も近い月数に戻します。 2番目の日付が最初の日付より遅い場合、0が返されます。
構文
NEAREST_MONTHS(Later_Date、Earlier_Date)
戻りタイプ 整数
例
NEAREST_MONTHS(date1、date2) date1が20/3/1997でdate2が23/7/1996の場合8を返します
NEAREST_MONTHS(date1、date2) date1が20/3/1997でdate2が1/2/1995の場合、26を返します
解決
これは、DCSアプリケーションと同じ方法で計算すると思われる関数として作成しました。バージョン9.2のSASで新しく追加されたいくつかの機能を使用します。これには、日付の連続配置が含まれます。また、時間的に前後に動作します(つまり、early_dateがlater_dateの後に負の整数を指定します)。間隔を超えて15日以上を次の月に丸めるためのカットオフとして使用しましたが、必要に応じて調整できます。
proc fcmp outlib=work.myfuncs.dates;
function nearest_months(later_date,earlier_date);
/* Return missing if inputs are missing */
if (earlier_date eq . ) OR (later_date eq . ) then
nearest_month=.;
else do;
/* Use 'cont' argument for continuous dates */
months=intck('MONTH',earlier_date,later_date,'cont');
if months < 0 then months=months+1;
days= later_date - intnx('month', earlier_date,months,'same');
/* Handle negatives (earlier dates) */
if months < 0 then do;
if days < -15 then months=months-1;
nearest_month=months;
end;
else do;
if days > 15 then months + 1;
nearest_month=months;
end;
end;
return(nearest_month);
endsub;
run;
options cmplib=work.myfuncs;
data _null_;
x=nearest_months('20Mar1997'd, '23JUL1996'd);
put x=;
x=nearest_months('20Mar1997'd, '01FEB1995'd);
put x=;
run;
これは参照と同じです:
x=8
x=26
他のヒント
INTNX
を使用して、切り上げるか切り下げるかを確認できます。例:
data _null_;
format x y date9. z 8.;
x="01APR08"d;
y="28APR08"d;
z=intck('MONTH',x,y);
* wl is x + z months;
wl=intnx('MONTH',x,z);
* wu is x + (z+1) months;
wu=intnx('MONTH',x,z+1);
* If y is closer to wu, then adjust z by 1;
if (abs(y-wu) lt abs(y-wl)) then z = z+1;
put x y z=;
run;
月を30日と定義すると、15日以内を0か月に切り捨て、16日以上を1か月に切り捨てます。 これは次の方法で実現できます。
data _null_;
format x y date9. z 8.;
x="14FEB09"d;
y="02MAR09"d;
z=round(intck('DAY',x,y)/31);
put x y z=;
run;
また、期間内の完全な月(「最初の1日から最後の1日」まで)を数えるアプローチを取り、残りの日を合計して、合計が0、1、または2か月になるかどうかを確認することもできます。 このように:
data _null_;
format x y date9. z 8.;
x="01FEB09"d;
y="31MAR09"d;
if day(x)=1 then do;
z=intck('MONTH',x,intnx('MONTH',y,0,'BEGINNING'))
+ round((intck('DAY',intnx('MONTH',y,0,'BEGINNING'),y))/31);
end;
else do;
z=intck('MONTH',intnx('MONTH',x,1,'BEGINNING'),intnx('MONTH',y,0,'BEGINNING'))
+ round((intck('DAY',x,intnx('MONTH',x,1,'BEGINNING'))+intck('DAY',intnx('MONTH',y,0,'BEGINNING'),y))/31);
end;
put x y z=;
run;
最初の方法は理解と保守が簡単ですが、2番目の方法は大きな間隔でより正確です(01FEB06から01FEB09は36か月ですが、方法1では35か月であることがわかります)。