问题描述
在 Stata 中,我试图评估与给定日期相比哪个给定生日是下一个。我的数据如下所示:
- 所有日期均采用每日格式 (%dD_m_Y),例如1926 年 1 月 18 日
- 变量
date
,它是所有其他日期应与之比较的参考日期 - 变量
birth1,birth2,birth3,birth4,birth5,birth6
包含所有可能的家庭成员的生日。
例如:有两个成年人 A 和 B 的家庭。A 的生日是 1977 年 11 月 20 日,B 人的生日是 1978 年 3 月 30 日。参考日期是 29.11.2020。我想知道下一个生日的人是谁,在上面的例子中是人B,因为人A在参考日期前一周过生日,所以这个家庭的下一个生日将在30日庆祝2021 年 3 月。
示例数据:
日期 | 出生1 | birth2 | birth3 | birth4 | 诞生5 | 诞生6 |
---|---|---|---|---|---|---|
02feb2021 | 15jan1974 | 27nov1985 | ||||
30nov2020 | 31aug1945 | 27jun1999 | 07apr1997 | |||
19nov2020 | 27sep1993 | 30dec1996 | ||||
29jan2021 | 29mar1973 | |||||
05dec2020 | 21jan1976 | 02oct1976 | 21jan1976 | 25may1995 | 1997 年 2 月 15 日 | |
25nov2020 | 25nov1943 | 29nov1946 | ||||
02feb2021 | 28apr1979 |
解决方法
已编辑为 2 月 29 日的帐户
*如果 date
年不是闰年,编辑会将生日为 2 月 29 日的人视为 3 月 1 日。如果这对您的特定用例没有意义,那么按照您认为合适的方式更改下面的代码应该很容易。
由于您想要的是当年的下一个生日而不是最近的生日,因此您可以使用 date
的年份和 birth{i}
的月份和日期为每个人的下一个生日创建一个日期。然后您可以简单地从每个家庭中获取最早的值。为了做到这一点,我重塑了long,并生成了一个人和家庭id
。
制作示例数据
clear
set obs 6
set seed 1996
generate date = floor((mdy(12,31,2020)-mdy(12,1,2015)+1)*runiform() + mdy(12,2015))
format date %td
forvalue i = 1/6 {
gen birth`i' = floor((mdy(12,1996)-mdy(12,1980)+1)*runiform() + mdy(12,1980)) if _n < `i' == 0
format birth`i' %td
}
replace birth6 = birth4 in 6 // want a tie
replace birth2 = date("29feb1996","DMY") in 3 // Feb 29
寻找下一个生日
gen household_id = _n
reshape long birth,i(date household_id) j(person)
drop if mi(birth)
gen person_next_birthday = mdy( month(birth),day(birth),year(date))
* TREAT FEB 29 as if they have a march 1 birthday in non-leap years
replace person_next_birthday = mdy(3,year(date)) if month(birth) == 2 ///
& day(birth) == 29 & mod(year(date),4)!=0
replace person_next_birthday = mdy( month(birth),year(date) + 1) if person_next_birthday < date
replace person_next_birthday = mdy(3,year(date)+1) if month(birth) == 2 ///
& day(birth) == 29 & mod(year(date) + 1,4)!=0 & person_next_birthday < date
format person_next_birthday %td
bysort household_id (person_next_birthday): gen next_bday = person_next_birthday[1]
format next_bday %td
drop person_next_birthday
reshape wide birth,i(date household_id next_bday) j(person)
gen next_bday_persons = ""
* Make a string to present household persons who have next bday
foreach v of varlist birth* {
local person = subinstr("`v'","birth","",.)
local condition = "month(`v') == month(next_bday) & day(`v') == day(next_bday)"
local condition_feb29 = "month(next_bday) == 3 & day(next_bday) == 1 & month(`v') == 2 & day(`v') == 29"
replace next_bday_persons = next_bday_persons + "|`person'" if `condition' | `condition_feb29'
}
replace next_bday_persons = regexr(next_bday_persons,"^\|","")
order next_bday_persons,after(next_bday)
最后一个循环是不必要的,但说明这对绑定是健壮的。