日付の形式を変更する

729 Views

April 15, 25

スライド概要

[第11回大阪sas勉強会]

profile-image

SAS言語を中心として,解析業務担当者・プログラマなのコミュニティを活性化したいです

シェア

またはPlayer版

埋め込む »CMSなどでJSが使えない場合

関連スライド

各ページのテキスト
1.

日付の形式を変更する エイツーヘルスケア株式会社 淺井友紀

2.

日付の形式を変換したい • dd/mmm/yyyy形式の日付の文字値を、yyyy-mm-dd形式の日付 の文字値に変換するマクロの紹介です。 • 動作例 (UN/UNKは詳細不明だけど文字が入ってきているものとしま す。 UN/UNKに限らず、日付としてあり得ない入力は詳細不明として マクロ内で扱います) • 01/Jan/2023 -> 2023-01-01 • UN/Jan/2023->2023-01 • UN/UNK/2023->2023 • UN/2023->2023 • 01/Jan-> --01-01 • 01/UNK/2023->2023---01

3.

マクロのパラメータ • %ST_DTC_DDMMMYYYY( _indt = 入力する日付変数(文字値 dd/mmm/yyyy形式), _outdt = 出力する日付変数(文字値 yyyy-mm-dd形式), _delim= 入力日付変数の区切り文字* ); *区切り文字は”で挟んで指定する(区切り文字がスペースの時に 対応するため) *区切り文字は統一されてないとマクロが正しく実行されない

4.

マクロ内でやっていること • 入力日付の区切り文字をスラッシュに置換 • V_DLIM_DATE = transtrn(strip(&_indt.) , &_delim., "/") ; • 年月日の要素で不足している個所を”--”で補完 • Jun/2023->--/Jun/2023, 01/Jun->01/Jun/----, 01//2023->01/-/2023 • 欠測として入っている要素を”--”に置換 • 日付をdd/mmm/yyyyからyyyy-mm-ddに変換

5.
[beta]
マクロ内でやっていること
• 欠測として入っている要素を”--”に置換
• UN/Jun/2023->--/Jun/2023, 05/UNK/9999->05/--/---• 様々ある「欠測として入っている文字」を拾うため正規表現を使用
• if prxmatch( "/0[1-9]|[1-9]|[1-2][0-9]|3[0-1]/" , strip(V_PRT_DATE) ) = 0 then
V_PRT_DATE = "--" ;
• if prxmatch(“/(JAN|FEB|MAR|APR|MAY|JUN|JUL|AUG|SEP|OCT|NOV|DEC)/” ,
strip(upcase(V_PRT_MONTH)) )=0 then V_PRT_MONTH = “--” ;
• if prxmatch( "/(?!9999)¥d{4}/" , strip(V_PRT_YEAR) ) = 0 then V_PRT_YEAR = "---" ;

• 日付けならUNや99、35等が欠測扱い、月はアルファベット以外を欠測、年
は数字4桁以外と9999を欠測扱いとしている
• 月と日の欠測を区別するために、日付が”--”なら”@--”と識別用の文字を付加
• @--/--/2025

• こんな要素ごとに分岐や、識別用の@の付加をせずとも、prxchangeで置換
できると思うのですがうまくいかず…正規表現って難しい…

6.

マクロ内でやっていること • dd/mmm/yyyyをyyyy/mm/ddに変換 • この時点で足りない要素を”--”で補完して、日付であり得ない入力を”-”に置き換えているので、--/Jan/2023や、05/--/2023等の形になっ ている • -が無ければ形式を変換 • &_outdt. = put(input(V_DT, ??date11.), yymmdd10.) ; • 日のみが欠測なら年月のみ変換 (--/Jan/2023) • if index(V_PRE_CONV, "@--") > 0 and index(V_PRE_CONV, "/--/") = 0 and index(V_PRE_CONV, "/----") = 0 then z = put(input( transtrn(V_PRE_CONV, "@--/", trimn("")), ??monyy8.), yymmd.) ; • 月日が欠測なら年のみ変換 • --/--/2023 -> 2023 他のパターンも変換していますが資料では省略します…

7.

出来ない事 • 2月の考慮 • 正規表現で0[1-9]|[1-9]|[1-2][0-9]|3[0-1]としているので、2/30等は欠測に なります • うるう年ではないときに2/29が来ても同様に欠測になります • そこまでを検知する分岐はちょっと諦めました… • 処理イメージ • data _null_ ; • a = "30/feb/2025" ; • b = put(input(a, ??date11.), yymmdd10.) ; • putlog a = b = ; • run ; • log • a=30/feb/2025 b=.

8.
[beta]
%macro ST_DTC_DDMMYYYY(_indt = ,_outdt = , _delim= ) ;
/*----_indt : store character value date ex: raw data date with ddmmmyy
_outdt : Character variable name to output with yyyy/mm/dd format
_delim : year, month, date separator
Only _delim should be enclosed in double-cotation marks. ex : " " or "-"
-----*/
V_DLIM_DATE = transtrn(strip(&_indt.) , &_delim., "/") ;
/*>>>>>---------- Fill in the missing elements with -- ----------<<<<<*/
length V_INDT_FILL $20 ;
if count(V_DLIM_DATE, "/") = 2 then do ;
if first(V_DLIM_DATE) = "/" then V_INDT_FILL = cats("--", V_DLIM_DATE) ;
else if index(V_DLIM_DATE,"//") then V_INDT_FILL = transtrn(V_DLIM_DATE, "//", "/--/") ;
else if first(reverse( strip(V_DLIM_DATE) )) = "/" then V_INDT_FILL = cats(V_DLIM_DATE, "----") ;
else V_INDT_FILL = V_DLIM_DATE ;
end ;
if count(V_DLIM_DATE,"/") = 1 then do ;
if prxmatch( "/\d{4}$/", strip(V_DLIM_DATE) ) = 0 then V_INDT_FILL = cats(V_DLIM_DATE,"/----") ;
if prxmatch( "/\d{4}$/", strip(V_DLIM_DATE) ) > 0 then V_INDT_FILL = cats( "--/" , V_DLIM_DATE) ;
end ;
if count(V_DLIM_DATE , "/") = 0 then do ;
if prxmatch( "/\d{4}/", strip(V_DLIM_DATE) ) > 0 then V_INDT_FILL = cats("--/--/" ,V_DLIM_DATE) ;
else if prxmatch( "/\d{2}/", strip(V_DLIM_DATE) ) > 0 then V_INDT_FILL = cats( V_DLIM_DATE, "/--/----" ) ;
else if prxmatch( "/(JAN|FEB|MAR|APR|MAY|JUN|JUL|AUG|SEP|OCT|NOV|DEC)/", strip(upcase(V_DLIM_DATE)) ) > 0 then V_INDT_FILL = cats("--/" , V
_DLIM_DATE, "/----" ) ;
else call missing(V_INDT_FILL) ;
end ;
/*>>>>>---------- Replace non-date value with -- ----------<<<<<*/
length V_PRT_DATE V_PRT_MONTH V_PRT_YEAR $8 ;
V_PRT_DATE = scan(V_INDT_FILL, 1, "/") ;
V_PRT_MONTH = scan(V_INDT_FILL, 2, "/") ;
V_PRT_YEAR = scan(V_INDT_FILL, 3, "/") ;
if prxmatch( "/0[1-9]|[1-9]|[1-2][0-9]|3[0-1]/"
, strip(V_PRT_DATE) )
= 0 then V_PRT_DATE = "--" ;
if prxmatch( "/(JAN|FEB|MAR|APR|MAY|JUN|JUL|AUG|SEP|OCT|NOV|DEC)/" , strip(upcase(V_PRT_MONTH)) ) = 0 then V_PRT_MONTH = "--" ;
if prxmatch( "/(?!9999)\d{4}/"
, strip(V_PRT_YEAR) )
= 0 then V_PRT_YEAR = "----" ;
/*>>>>>---------- after replace date ----------<<<<<*/
length V_PRE_CONV $20 ;
V_PRE_CONV = cats(V_PRT_DATE, "/", V_PRT_MONTH, "/", V_PRT_YEAR ) ;
if first(strip(V_PRE_CONV)) = "-" then V_PRE_CONV = cats("@", V_PRE_CONV) ;
/*>>>>>---------- convet ddmmmyyy to yyyymmdd ----------<<<<<*/
/*---------- complete date ----------*/
length &_outdt. $20 ;
if index(V_PRE_CONV, "--") = 0 then &_outdt. = put(input(V_PRE_CONV, ??date11.), yymmdd10.) ;
/*---------- one missing part ----------*/
if index(V_PRE_CONV, "@--") > 0 and index(V_PRE_CONV, "/--/") = 0 and index(V_PRE_CONV, "/----") = 0 then z = put(input( transtrn(V_PRE_CONV, "
@--/", trimn("")), ??monyy8.), yymmd.) ;
if index(V_PRE_CONV, "@--") = 0 and index(V_PRE_CONV, "/--/") > 0 and index(V_PRE_CONV, "/----") = 0 then do ;
&_outdt. = cats( transtrn(put(input(transtrn(V_PRE_CONV, "/--/", "/Jan/"), ??date11.), yymmdd10.) , "-01-" , "---") ) ;
end ;

9.
[beta]
if index(V_PRE_CONV, "@--") = 0 and index(V_PRE_CONV, "/--/") = 0 and index(V_PRE_CONV, "/----") > 0 then do ;
&_outdt. = cats( transtrn(put(input(transtrn(V_PRE_CONV, "/----", "2020" ), ??date11.), yymmdd10.), "2020", "-") ) ;
end ;
/*---------- two missing part ----------*/
if index(V_PRE_CONV, "@--") > 0 and index(V_PRE_CONV, "/--/") > 0 and index(V_PRE_CONV, "/----") = 0 then &_outdt. = scan(V_PRE_CONV, 3, "/" )
;
if index(V_PRE_CONV, "@--") > 0 and index(V_PRE_CONV, "/--/") = 0 and index(V_PRE_CONV, "/----") > 0 then do ;
&_outdt. = strip(put(input(transtrn(transtrn(V_PRE_CONV, "@--", "01") , "/----", "2020"), ??date11.) , yymmdd10.)) ;
&_outdt. = transtrn(transtrn(&_outdt., "2020", "-"), "-01", "--") ;
end ;
if index(V_PRE_CONV, "@--") = 0 and index(V_PRE_CONV, "/--/") > 0 and index(V_PRE_CONV, "/----") > 0 then do ;
&_outdt. = strip(put(input(transtrn(transtrn(V_PRE_CONV, "/--/", "/Jan/") , "/----", "2020"), ??date11.) , yymmdd10.)) ;
&_outdt. = transtrn(transtrn(&_outdt., "2020", "-"), "-01-", "---") ;
end ;
/*>>>>>---------- three missing part ------<<<<<*/
if index(V_PRE_CONV, "@--") > 0 and index(V_PRE_CONV, "/--/") > 0 and index(V_PRE_CONV, "/----") > 0 then call missing(&_outdt.) ;
if missing(V_PRE_CONV) = 1 then call missing(&_outdt.) ;
%mend ST_DTC_DDMMYYYY ;