Я думаю, что ответы многих людей были до того, как ОП дала важную информацию о том, как fy
играет роль функции (правка: многие читали это правку, и теперь их ответы также обновляются). OP хочет количество дней между admission
и discharge
, которое проходит в течение финансового года (с 1819 по 01 апреля 2018 года по 31 марта 2019 года). И, очевидно, все знают, что число дней должно быть разделено на календарный месяц.
from datetime import datetime, timedelta
# Function taken from https://stackoverflow.com/a/13565185/9462009
def lastDateOfThisMonth(any_day):
next_month = any_day.replace(day=28) + timedelta(days=4)
return next_month - timedelta(days=next_month.day)
def monthlyBeddays(admission, discharge, fy):
startFy = datetime.strptime('01-Apr-'+fy[:2], '%d-%b-%y')
endFy = datetime.strptime('01-Apr-'+fy[2:], '%d-%b-%y')
admissionDate = datetime.strptime(admission, '%d-%b-%Y')
dischargeDate = datetime.strptime(discharge, '%d-%b-%Y')
monthDates = {'Jan':0,'Feb':0,'Mar':0,'Apr':0,'May':0,'Jun':0,'Jul':0,'Aug':0,'Sep':0,'Oct':0,'Nov':0,'Dec':0}
# if admitted after end of fy or discharged before beginning of fy, zero days counted
if admissionDate > endFy or dischargeDate < startFy:
return monthDates
if admissionDate < startFy:
# Jump ahead to start at the first day of fy if admission was prior to the beginning of fy
now = startFy
else:
# If admission happened at or after the first day of fy, we begin counting from the admission date
now = admissionDate
while True:
month = datetime.strftime(now,'%b')
lastDateOfMonth = lastDateOfThisMonth(now)
if now >= endFy:
# If now is greater or equal to the first day of the next fy (endFy), we don't care about any of the following dates within the adm/dis date range
break
if month == datetime.strftime(dischargeDate,'%b') and datetime.strftime(now, '%Y') == datetime.strftime(dischargeDate, '%Y') and now >= startFy:
# If we reach the discharge month, we count this month and we're done
monthDates[month] = (dischargeDate - now).days # not adding one since in your example it seemed like you did not want to count the dischargeDate (Mar:4)
break
elif now < startFy:
# If now is less than the first day of this fy (startFy), we move on from this month to the next month until we reach this fy
pass
else:
# We are within this fy and have not reached the discharge month yet
monthDates[month] = (lastDateOfMonth - now).days + 1
month = datetime.strftime(now, '%b')
now = lastDateOfMonth + timedelta(days=1) # advance to the 1st of the next month
return monthDates
# Passes all six scenarios
# Scenario #1: admitted before fy, discharged before fy (didn't stay at all during fy)
print(monthlyBeddays("01-Jan-2018", "30-Mar-2018", '1819')) # {'Jan': 0, 'Feb': 0, 'Mar': 0, 'Apr': 0, 'May': 0, 'Jun': 0, 'Jul': 0, 'Aug': 0, 'Sep': 0, 'Oct': 0, 'Nov': 0, 'Dec': 0}
# Scenario #2: admitted before fy, discharged during fy
print(monthlyBeddays("01-Jan-2018", "30-May-2018", '1819')) # {'Jan': 0, 'Feb': 0, 'Mar': 0, 'Apr': 30, 'May': 29, 'Jun': 0, 'Jul': 0, 'Aug': 0, 'Sep': 0, 'Oct': 0, 'Nov': 0, 'Dec': 0}
# Scenario #3: admitted during fy, discharged during fy
print(monthlyBeddays("15-Apr-2018", "30-May-2018", '1819')) # {'Jan': 0, 'Feb': 0, 'Mar': 0, 'Apr': 16, 'May': 29, 'Jun': 0, 'Jul': 0, 'Aug': 0, 'Sep': 0, 'Oct': 0, 'Nov': 0, 'Dec': 0}
# Scenario #4: admitted during fy, discharged after fy
print(monthlyBeddays("15-Apr-2018", "30-May-2019", '1819')) # {'Jan': 31, 'Feb': 28, 'Mar': 31, 'Apr': 16, 'May': 31, 'Jun': 30, 'Jul': 31, 'Aug': 31, 'Sep': 30, 'Oct': 31, 'Nov': 30, 'Dec': 31}
# Scenario #5: admitted before fy, discharged after fy (stayed the whole fy)
print(monthlyBeddays("15-Mar-2018", "30-May-2019", '1819')) # {'Jan': 31, 'Feb': 28, 'Mar': 31, 'Apr': 30, 'May': 31, 'Jun': 30, 'Jul': 31, 'Aug': 31, 'Sep': 30, 'Oct': 31, 'Nov': 30, 'Dec': 31}
# Scenario #6: admitted after fy, discharged after fy (didn't stay at all during fy)
print(monthlyBeddays("15-Mar-2018", "30-May-2019", '1718')) # {'Jan': 0, 'Feb': 0, 'Mar': 17, 'Apr': 0, 'May': 0, 'Jun': 0, 'Jul': 0, 'Aug': 0, 'Sep': 0, 'Oct': 0, 'Nov': 0, 'Dec': 0}