python / pandas查找两个日期之间的年数

时间:2017-03-01 00:21:23

标签: python date pandas datetime

我有一个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_startdate_end属于“datetime”dtype。我想要一个新列,即两个日期之间的年数。获得两个日期之间的天数(df['diff'] = df.date_end - df.date_start)很简单但是我遇到了麻烦,因为在给定天数内经过的年数取决于“何时”发生的日期,因为闰年。

这类似于一个人的年龄。我尝试过针对类似问题调整大量解决方案,但很多问题都是关于两个日期之间的天数或周数。我已经有办法获得没有考虑闰年的年数,但我想要比这更正确。

5 个答案:

答案 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()函数来对其进行计算。

代码将开始日期和结束日期之间的时间段分为三个时间段:

  1. 从开始日期到该年末
  2. 开始日期和结束日期之间的整年,以及
  3. 从包含end_date的年初开始到end_date。

它还处理起始日期和结束日期在同一年,连续年份等情况下的情况。

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)

对于这种情况,我认为我有一个更好的主意:

  1. 获得年差;
  2. 如果(start_month <end_month)或(start_month == end_monthstart_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)