STATAで日付をうまく扱えず悩んでいたので、自分が必要な範囲で調べて整理してみた。

ポイントは、
  • 日付変数をいったん日付らしい表示の文字列にしておくこと(2022/3/5や5th/Mar/22など)
  • 次にdate関数でencoded date(※)に変換された新しい日付変数を作成する。ここで数値に変換される。
  • encoded dateになっている新しい日付変数を使って、表示を対人可読なものにしたり、年・月・日を取り出したり、好きなようにする。
※1960年1月1日を基準(0)としたSTATA上の日数

1. 日付変数をいったん日付らしい表示の文字列にする

はじめに、日付変数をいったん文字列にする。なぜかというと、次の手順でdate関数を使って、STATAが年月日を認識するための数値(encoded date※)に変換するのだが、変換前の値が文字列である必要があるからだ。
※encoded date: 1960年1月1日を基準(0)とした日数。STATAは1960年1月1日から何日目かを数えることで日付を認識する。

従って、
  • もし日付変数が、すでにencoded dateになっているのであれば、この手順は飛ばしてよい。
また、
  • もし日付変数が、日付を表す文字列(2022/3/9, 09Mar2022, 2022年3月9日など)になっていれば、やはりこの手順は飛ばしてよい。

もし日付変数が、年月日を表現した数値(20220308, 220308など)になっている場合、STATAが年(Y)・月(M)・日(D)を認識できるようにいったん値を文字列に変更しておくのが望ましい。

やり方は簡単。tostringを使うだけ。
例えば下記のような数値の日付変数があるとする。
日付変数1

これを数値変換し、新しく「日付_文字列」という変数に格納する。
tostring 日付変数, gen(日付_文字列)
日付変数2

そのままの変数名で置換したい場合はオプションの, gen()を, replaceに変更すればよい。

2. date関数でencoded dateに変換された新しい日付変数を作る

文字列(保存形式がstrで始まる変数)として格納されている日付変数を、date関数を使ってSTATAが日付と認識できるencoded dateに変換していく。

date関数は:
date(変数名, "Y,M,Dの組み合わせ")
である。引数は「変数名」と「Y,M,Dの組み合わせ」の2つである。
※実は3つ目もあるのだが、これは20/March/9thなどように、年が2桁の場合に、1920年なのか2020年なのかを区別するために用いられる。ここでは割愛するので必要な場合は.help dateをご参照(後日別途書くかも?)

例えば"2020309"のような形式で保存されている変数名「日付_文字列」の場合、年(Y)・月(M)・日(D)なので、新たに変数名「日付_ed」にSTATA用の日付変数を作るとすると、date関数を使って
gen 日付_ed = date(日付_文字列, "YMD")
とすれば、

日付変数3

となって、日付_文字列変数に格納された日付のencoded date(1960年1月1日から数えた日数)が作成される。

同様に、日付変数が例えば下記のような表示になっていても:

日付変数4

date関数を使って
gen 日付_ed_jp = date(日付変数jp, "YMD")

gen 日付_ed_en = date(日付変数en, "DMY")

とすれば、
日付変数5

このように、(当たり前だが)まったく同じencoded dateに変換される。encoded dateの値は単なる数値(ここではfloat)であり、これは「2020年3月9日は、1960年1月1日から21,983日経っている」ことと同義である。

文字列の日付がdate関数でencoded dateに変換されたら、
・formatで対人可読な表示形式に変更する
・年だけ、月だけ、日だけを取り出す。
・2つの日付の間の日数を計算する
などの作業を行うことができるようになる、というわけである。

ここでは「formatで対人可読な表示形式に変更する」と「年だけ、月だけ、日だけを取り出す」の2つだけを紹介する(日数の計算はencoded dateを引き算すればよいだけ。なぜならそれは単なる数値でしかないから)

3. formatでencoded dateを対人可読な表示に変換する

date関数でencoded dateに変換された値を人間でもわかるような表現にするには、formatを使って対人可読な表示形式に変更する。

formatの仕方は

format 変数a 変数b .. 指定のフォーマット

である。

日付に関するフォーマットは%tdである。

例えば、上記で作った3つのencoded dateの日付変数について、
format 日付_ed 日付_ed_jp 日付_ed_en %td

とすれば、

日付変数6




日付変数7

となる。デフォルトの表記で問題ない人は表示形式の話は以上である。

もしさらに好みの表示形式に変更したい場合は、%tdのあとに日時フォーマットの詳細を指定することで、様々な表現に変更できる。

一例をあげると:
format 日付_ed %tdCY/n/D
日付変数8

format 日付_ed %tdMonth_dd,_CCYY
日付変数9

などである。なんで月はMやmではなくnなんだ!と思われるかもしれないが、これは分(minute)と区別するためだろう。

その他にも色々な表現の仕方があり(残金ながら日本語表記はできなかった)、ここでは紹介しきれないので、フォーマットのオプションはSTATAの(date time display formats)マニュアルを参照してほしい。


4. encoded dateから日・月・年だけを取り出す

encoded dateになっていれば、日・月・年だけを取り出すこともできる。それぞれday関数, month関数, year関数を使う。

gen 日 = day(日付_ed)
gen 月 = month(日付_ed)
gen 年 = year(日付_ed)

とすれば、

日付変数10


紛らわしいことだが、
  • 文字列の日付変数をencoded date(数値)に変換するのはdate関数
  • encodedされた数値から日付を取り出すのはday関数
なので注意。

おまけ:monthly関数やyearly関数でencodeされた新しい月・年の変数も作れる

これまで文字列の日付を数値の日付に変換する方法を見てきたが、文字列の年月や文字列のも、同様にencoded month(1960年1月からの月数)やencoded year(単なる西暦)に変換することができる。

方法は日付と同様であるが、用いる関数はmonthly関数及びyearly関数である。

例えば
日付変数12

のような文字列になっている月・年の変数があるとして、

gen ym_ed = monthly(ym, "YM")

gen year_ed = yearly(year, "Y")

とすると、

日付変数13

となる。

実際にやってみて気になった点としては、
  • 文字列の年月は、日付の時のように柔軟に対応しない(202003や2020年3月のような日本語表記だとダメ)2020/03や2020-03のようになっているとうまくいく。
  • 年はencoded yearにする意味はあるのだろうか??

といったところだが、使う場面はどれほどあるだろうか。