0

Let's have two variables:

  1. start_date
  2. days_of_months::list (example: [1,2,10,31])

Output: a date>=start_date which ("%d") = one of the list members. The output date must be as close as possible to the start_date.

Examples

start_date: 2020-11-17

days_of_month: [5,10,20]

output: 2020-11-20

start_date: 2020-11-17

days_of_month: [5,10]

output: 2020-12-05

start_date: 2020-12-17

days_of_month: [5,10]

output: 2021-01-05

start_date: 2021-02-17

days_of_month: [5,10,31]

output: 2021-03-05

start_date: 2021-04-17

days_of_month: [31]

output: 2021-05-31 (April of 2021 has not 31 days)

Suggested answer:

from calendar import monthrange
from datetime import datetime
from datetime import timedelta

def find_condition_date(start_date,days_month_list):
    year = int(start_date.strftime("%Y"))
    month = int(start_date.strftime("%m"))
    day = int(start_date.strftime("%d"))
    
    current_month_days = monthrange(year, month)[1]
    
    if(day in days_month_list):
        return start_date
    else:
        for day_of_month_selected in days_month_list:
            if(day_of_month_selected>day and day_of_month_selected<=current_month_days):
                add_days = day_of_month_selected - day
                start_date = start_date + timedelta(days=add_days)
                return start_date
            
        selected_index = 0
        total_days_selected = len(days_month_list)
        if(month==12):
            year+=1
            month = 1
        else:
            month +=1
        current_month_days = monthrange(year,month)[1]
        
        while(True):
            if(selected_index<total_days_selected):
                first_day_of_month_selected = int(days_month_list[selected_index])
                if(current_month_days>=first_day_of_month_selected):
                    return datetime(year,month,first_day_of_month_selected).date()
                else:
                    selected_index = 0
                    if(month==12):
                        year+=1
                        month = 1
                    else:
                        month +=1
                    current_month_days = monthrange(year,month)[1]
            else:
                selected_index = 0
                if(month==12):
                    year+=1
                    month = 1
                else:
                    month +=1
                current_month_days = monthrange(year,month)[1]

#Example 1          
start_date = datetime(2020,11,17)
days_month_list = [5,10,20]
print(find_condition_date(start_date,days_month_list))

#Example 2          
start_date = datetime(2020,11,17)
days_month_list = [5,10]
print(find_condition_date(start_date,days_month_list))

#Example 3          
start_date = datetime(2020,12,17)
days_month_list = [5,10]
print(find_condition_date(start_date,days_month_list))

#Example 4
start_date = datetime(2021,2,17)
days_month_list = [5,10,31]
print(find_condition_date(start_date,days_month_list))

#Example 5
start_date = datetime(2021,4,17)
days_month_list = [31]
print(find_condition_date(start_date,days_month_list))

The above code seems to work as expected.

Chris P
  • 2,059
  • 4
  • 34
  • 68

2 Answers2

0

First, extract the day from start_date

Then sort the month days and iterate over the sorted array to find the first value that is larger than the start date

Tamir
  • 1,224
  • 1
  • 5
  • 18
  • but if there is no larger value then i must increase the month – Chris P Nov 16 '20 at 23:02
  • check the examples, sometimes the month and the year also changes – Chris P Nov 16 '20 at 23:03
  • If there is no day that is suitable (like your last example) you can check it using the `datetime` module and increase the month and repeat the process Or you could first extract the year and month as a starting point – Tamir Nov 16 '20 at 23:03
  • Any special condition when month in start_datetime is February? – Chris P Nov 16 '20 at 23:05
  • Let's say you have 29 in your list and the month is February, just check if the date is valid using `datetime` and it will return that it is not. In this case just increase the month to March and choose the first suitable day – Tamir Nov 16 '20 at 23:07
  • Answered question on how to check date validity: https://stackoverflow.com/questions/9987818/in-python-how-to-check-if-a-date-is-valid – Tamir Nov 16 '20 at 23:08
  • 1
    Ok, that's my first thought about this issue. I will accept your answer (maybe i preffered more if it has some python code...Anyway... – Chris P Nov 16 '20 at 23:10
0

Iterate over the available days until we find the next closest valid date(incrementing month/year as required):

from datetime import date


def valid_date(y, m, d):
    try:
        date(y, m, d)
        return True
    except ValueError:
        return False


def find_next_date(start_date, days_of_month):
    current_year, current_month, current_day = map(int, start_date.split('-'))
    while True:
        for day in days_of_month:
            if day >= current_day and valid_date(current_year, current_month, day):
                return f'{current_year}-{current_month:02}-{day:02}'

        current_month += 1
        current_day = 1
        if current_month > 12:
            current_month = 1
            current_year += 1


assert find_next_date('2020-11-17', [5, 10, 20]) == '2020-11-20'
assert find_next_date('2020-11-17', [5, 10]) == '2020-12-05'
assert find_next_date('2020-12-17', [5, 10]) == '2021-01-05'
assert find_next_date('2021-02-17', [5, 10, 31]) == '2021-03-05'
assert find_next_date('2021-04-17', [31]) == '2021-05-31'
Terry Spotts
  • 3,527
  • 1
  • 8
  • 21