我有一个pandas数据框,其中包含两个包含日期的列。我想知道两个日期之间的年数,同时考虑闰年。
理想的解决方案不假设一年总是有一定天数。因为岁月并不总是有365天。
示例数据:
date_end date_start
2010-02-09 1933-03-03
2010-03-19 1924-04-08
2010-04-19 1924-04-08
2010-09-06 1924-04-08
2010-09-24 1924-04-08
2010-01-09 1933-04-29
2010-02-26 1933-04-29
2010-01-31 1953-06-10
2010-07-07 1928-11-14
2010-12-01 1974-11-17
date_start
和date_end
属于“datetime”dtype。我想要一个新列,即两个日期之间的年数。获得两个日期之间的天数(df['diff'] = df.date_end - df.date_start
)很简单但是我遇到了麻烦,因为在给定天数内经过的年数取决于“何时”发生的日期,因为闰年。
这类似于一个人的年龄。我尝试过针对类似问题调整大量解决方案,但很多问题都是关于两个日期之间的天数或周数。我已经有办法获得没有考虑闰年的年数,但我想要比这更正确。
答案 0 :(得分:4)
假设您想将一年定义为365天,那么您可以这样做:
>> df
date_end date_start is_leapyear
0 2016-02-28 2015-02-28 0
1 2017-02-28 2016-02-28 1
2 2018-02-28 2017-02-28 0
>> df['diff_in_days'] = df['date_end'] - df['date_start']
>> df['diff_in_years'] = df["diff_in_days"] / timedelta(days=365)
>> print df[["date_end", "date_start", "diff_in_years"]]
>> df
date_end date_start is_leapyear diff_in_years
0 2016-02-28 2015-02-28 0 1.00000
1 2017-02-28 2016-02-28 1 1.00274
2 2018-02-28 2017-02-28 0 1.00000
正如您所看到的,在有额外日子(2月29日)的年份,日期之间已经过了更多时间。在你的情况下,这将是:
date_end date_start diff_in_years
0 2010-02-09 1933-03-03 76.991781
1 2010-03-19 1924-04-08 86.002740
2 2010-04-19 1924-04-08 86.087671
3 2010-09-06 1924-04-08 86.471233
4 2010-09-24 1924-04-08 86.520548
5 2010-01-09 1933-04-29 76.750685
6 2010-02-26 1933-04-29 76.882192
7 2010-01-31 1953-06-10 56.682192
8 2010-07-07 1928-11-14 81.698630
9 2010-12-01 1974-11-17 36.063014
另一方面,如果你只是想要多年的差异。即减去发生日期的年份(不论发生日期的时间)。然后你可以这样做:
df['date_end_year'] = df.date_end.apply(lambda x: x.year)
df['date_start_year'] = df.date_start.apply(lambda x: x.year)
df['diff_in_years'] = df['date_end_year'] - df['date_start_year']
print df[["date_end", "date_start", "diff_in_years"]]
date_end date_start diff_in_years
0 2016-02-28 2015-02-28 1
1 2017-02-28 2016-02-28 1
2 2018-02-28 2017-02-28 1
在你的情况下,这将是:
date_end date_start diff_in_years
0 2010-02-09 1933-03-03 77
1 2010-03-19 1924-04-08 86
2 2010-04-19 1924-04-08 86
3 2010-09-06 1924-04-08 86
4 2010-09-24 1924-04-08 86
5 2010-01-09 1933-04-29 77
6 2010-02-26 1933-04-29 77
7 2010-01-31 1953-06-10 57
8 2010-07-07 1928-11-14 82
9 2010-12-01 1974-11-17 36
答案 1 :(得分:1)
需要解决完全相同的问题,并在下面创建了一个num_years()函数来对其进行计算。
代码将开始日期和结束日期之间的时间段分为三个时间段:
它还处理起始日期和结束日期在同一年,连续年份等情况下的情况。
def num_days_in_year(date: pd.Timestamp):
return 366 if date.is_leap_year else 365
def num_years(start_date: pd.Timestamp, end_date: pd.Timestamp) -> float:
"""
Compute the number of years between two given dates, accounting
for leap years.
:param start_date: Start date as Pandas Timestamp
:param end_date: End date as Pandas Timestamp
:return: float representing the number of years
"""
start_year = start_date.year
end_year = end_date.year
years = 0.0
if start_year != end_year:
send = start_date + pd.offsets.YearEnd()
years += (send - start_date).days / num_days_in_year(start_date)
if end_year > start_year + 1:
years += end_year - start_year- 1
if start_year == end_year:
start = start_date
else:
start = end_date - pd.offsets.YearBegin()
years += (end_date - start).days / num_days_in_year(end_date)
return years
答案 2 :(得分:1)
起初,我尝试使用praveen的答案,但发现一件事并不那么直观: 如果开始日期属于a年而结束日期不属于a年,则结果将不是整数,尽管开始日期和结束日期的月和日都相同,因为开始日期使用366,结束日期使用365。
我的想法是计算从开始日期到结束日期之前的整年。 然后,计算两次之间的天数。日期之后的整年”,然后将其除以通常的365或366(如果没有)。开始日期或结束日期之后的整整一年属于leap年。
def num_years(stdt: pd.Timestamp, endt: pd.Timestamp):
stYr = stdt.year
stMon = stdt.month
stDay = stdt.day
enYr = endt.year
rv = 0
# num of full years
calcStdt = pd.Timestamp(year=enYr, month=stMon, day=stDay)
if calcStdt > endt:
calcStdt = pd.Timestamp(year=enYr - 1, month=stMon, day=stDay)
rv = enYr - 1 - stYr
else:
rv = enYr - stYr
# remaining period less than a year
if (calcStdt.is_leap_year==True) | (endt.is_leap_year==True):
rv = rv + (endt-calcStdt).days/366
else:
rv = rv + (endt-calcStdt).days/365
return rv
# Test
print(num_years(pd.Timestamp(year=2000, month=1, day=10), pd.Timestamp(year=2004, month=1, day=10)))
print(num_years(pd.Timestamp(year=2000, month=5, day=10), pd.Timestamp(year=2004, month=5, day=10)))
print(num_years(pd.Timestamp(year=2001, month=1, day=10), pd.Timestamp(year=2004, month=1, day=10)))
print(num_years(pd.Timestamp(year=2001, month=5, day=10), pd.Timestamp(year=2004, month=5, day=10)))
答案 3 :(得分:0)
对于这种情况,我认为我有一个更好的主意:
start_month
<end_month
)或(start_month
== end_month
和start_day
<end_day
),则减去1。第二个条件基本上是检查上一整年是否已经过去。
可以使用熊猫系列来完成。可能的实现之一:
(
df.end_date.dt.year - df.start_date.dt.year
-
(
(df.end_date.dt.month < df.start_date.dt.month)
|
(
(df.end_date.dt.month == df.start_date.dt.month)
&
(df.end_date.dt.day < df.start_date.dt.day)
)
).astype(int)
)
假定使用pd.to_datetime
将列转换为日期时间。
答案 4 :(得分:-1)
您可以将列转换为年份,并简单地获取年份差数:
df.date_end.apply(lambda x: x.year) - df.date_start.apply(lambda x: x.year)