3 回答

TA貢獻1876條經驗 獲得超7個贊
這可以在不轉換為日期類型的情況下進行計算,但邊緣情況除外,其中日期是該月的最后一天(它們實際上對應于下個月的第零天)。
from datetime import date
def isLastDay(y,m,d):
return date.fromordinal(date(y,m,d).toordinal()+1).month != m
def legalMonthDif(date1,date2):
y1,m1,d1 = map(int,date1.split("-"))
y2,m2,d2 = map(int,date2.split("-"))
if isLastDay(y1,m1,d1): m1,d1 = m1+1,0
if isLastDay(y2,m2,d2): m2,d2 = m2+1,0
return y2*12+m2 -y1*12-m1 -(d2<d1)
輸出:
legalMonthDif('2019-08-15','2020-02-05') #5
legalMonthDif('2019-08-31','2019-11-30') #3
legalMonthDif('2019-08-25','2019-09-10') #0
legalMonthDif('2019-08-25','2019-09-25') #1
legalMonthDif('2019-08-31','2019-11-30') #3
legalMonthDif('2019-08-01','2019-12-01') #4
legalMonthDif('2019-08-31','2019-12-01') #3
legalMonthDif('2019-08-15','2019-12-01') #3
您也可以通過實現daysOfMonth函數來計算任何月份中的天數,完全無需datetime庫即可完成此操作:
def daysOfMonth(y,m):
return 30+(m+m//8)%2-(m==2)*(2-(y%4==0 and not y%100==0 or y%400==0))
def legalMonthDif(date1,date2):
y1,m1,d1 = map(int,date1.split("-"))
y2,m2,d2 = map(int,date2.split("-"))
if daysOfMonth(y1,m1) == d1: m1,d1 = m1+1,0
if daysOfMonth(y2,m2) == d2: m2,d2 = m2+1,0
return y2*12+m2 -y1*12-m1 -(d2<d1)

TA貢獻1821條經驗 獲得超5個贊
我最終編寫了以下函數,這些函數捕獲了此立法的預期功能:
def find_corresponding_date(start_date):
day = start_date.day
month = start_date.month
year = start_date.year
next_month = month + 1
next_year = year
if month == 12:
next_month = 1
next_year = year + 1
try:
new_date = py_datetime(year=next_year, month=next_month, day=day)
except ValueError:
next_month = next_month + 1
if next_month == 13:
next_month = 1
next_year = next_year + 1
new_date = py_datetime(year=next_year, month=next_month, day=1)
return new_date
else:
return new_date
def toPyDateTime(numpyDate):
return py_datetime.strptime(str(numpyDate), "%Y-%m-%d")
def count_months(sdate, edate):
start_date = toPyDateTime(sdate)
end_date = toPyDateTime(edate)
count = 0
corres_date = start_date
while(True):
corres_date = find_corresponding_date(corres_date)
if(corres_date > end_date):
return count
break
else:
count = count + 1

TA貢獻1880條經驗 獲得超4個贊
dates = [('2019-07-16','2019-08-15'),('2019-08-31','2019-09-30'),
('2019-08-15','2020-02-05'),('2019-08-31','2019-11-30'),
('2019-08-25','2019-09-10'),('2019-08-25','2019-09-25'),
('2019-08-31','2019-12-01'),('2019-08-15' , '2019-12-01'),
('2019-08-01', '2019-11-30'),('2019-08-01', '2019-12-01')]
使用熊貓日期時間功能。這依賴于這樣一個事實,即如果結果日期不存在,則在時間戳中添加月份將被截斷到月底 - 提供一種測試規范的(b)(ii)部分的方法。
import pandas as pd
def f(a,b):
earlier,later = sorted((a,b))
rel_months = later.month - earlier.month
delta_months = rel_months + (later.year - earlier.year) * 12
period_end = earlier + pd.DateOffset(months=delta_months)
# sentinals for implementing logic of (b)(ii) of the definition
period_end_isEOM = period_end + pd.tseries.offsets.MonthEnd(0)
later_isEOM = later == later + pd.tseries.offsets.MonthEnd(0)
next_month = period_end + pd.tseries.offsets.MonthBegin(0)
# begin with the delta - period_end == later - then adjust
months = delta_months
# this is straightforward
if period_end > later:
months -= 1
# did period_end get truncated to the end of a month
if period_end_isEOM and (period_end.day < earlier.day):
# actual end of period would be beginning of next month
if later < next_month: # probably also means later_isEOM or later == period_end
months -= 1
return months
for a,b in dates:
a, b = map(pd.Timestamp, (a,b))
c = f(a,b)
print(f'{a.date()} - {b.date()} --> {c}')
>>>
2019-07-16 - 2019-08-15 --> 0
2019-08-31 - 2019-09-30 --> 0
2019-08-15 - 2020-02-05 --> 5
2019-08-31 - 2019-11-30 --> 2
2019-08-25 - 2019-09-10 --> 0
2019-08-25 - 2019-09-25 --> 1
2019-08-31 - 2019-12-01 --> 3
2019-08-15 - 2019-12-01 --> 3
2019-08-01 - 2019-11-30 --> 3
2019-08-01 - 2019-12-01 --> 4
>>>
pd.時間戳是datetime.datetime
這似乎有效 - 只有OP可以判斷 - 但我忍不住想到我仍然沒有利用一些內置功能。應該能夠子類熊貓。日期偏移并自定義它以使計算更容易。
使用 Pandas.DateOffset 子類的解決方案。
from pandas import DateOffset, Timestamp
from pandas.tseries.offsets import MonthBegin
class LegislativeMonth(DateOffset):
def __init__(self, n=1, normalize=False, months=1):
# restricted to months
kwds = {'months':months}
super().__init__(n=1, normalize=False, **kwds)
def apply(self,other):
end_date = super().apply(other)
if end_date.day < other.day:
# truncated to month end
end_date = end_date + MonthBegin(1)
return end_date
for a,b in dates:
earlier,later = sorted(map(Timestamp, (a,b)))
delta_months = later.month - earlier.month
delta_months += (later.year - earlier.year) * 12
end_of_period = earlier + LegislativeMonth(months=delta_months)
if end_of_period > later:
delta_months -= 1
print(f'{earlier.date()} - {later.date()} --> {delta_months}')
# another
one_month = LegislativeMonth(months=1)
for a,b in dates:
earlier,later = sorted(map(Timestamp, (a,b)))
end_period = earlier
months = 0
while later >= end_period + one_month:
months += 1
end_period += one_month
print(f'{earlier.date()} - {later.date()} --> {months}')
最后,如果您確保以較早的日期作為第一項來調用它,它看起來像是會做您想要的 -relativedelta(earlier,later)
from datetime import datetime
from dateutil.relativedelta import relativedelta
for a,b in dates:
## earlier,later = sorted(map(Timestamp, (a,b)))
earlier,later = sorted((datetime.strptime(a, '%Y-%m-%d'),
datetime.strptime(b, '%Y-%m-%d')))
rd = relativedelta(earlier,later)
print(f'{earlier.date()} - {later.date()} --> {abs(rd.months)}')
使用此帖子頂部的日期,所有日期都將打印以下內容:
2019-07-16 - 2019-08-15 --> 0
2019-08-31 - 2019-09-30 --> 0
2019-08-15 - 2020-02-05 --> 5
2019-08-31 - 2019-11-30 --> 2
2019-08-25 - 2019-09-10 --> 0
2019-08-25 - 2019-09-25 --> 1
2019-08-31 - 2019-12-01 --> 3
2019-08-15 - 2019-12-01 --> 3
2019-08-01 - 2019-11-30 --> 3
2019-08-01 - 2019-12-01 --> 4
添加回答
舉報