Checking if birthday falls within 7 days

时间:2018-02-03 09:41:12

标签: python-3.x

I currently have two dictionaries set up like so

D = {'Jan': {'days': 31, 'nextmo': 'Feb', 'prevmo': 'Dec'},
 'Feb': {'days': 29, 'nextmo': 'Mar', 'prevmo': 'Jan'},
 'Mar': {'days': 31, 'nextmo': 'Apr', 'prevmo': 'Feb'},
 'Apr': {'days': 30, 'nextmo': 'May', 'prevmo': 'Mar'}, 
 'May': {'days': 31, 'nextmo': 'Jun', 'prevmo': 'Apr'},
 'Jun': {'days': 30, 'nextmo': 'Jul', 'prevmo': 'May'},
 'Jul': {'days': 31, 'nextmo': 'Aug', 'prevmo': 'Jun'},
 'Aug': {'days': 31, 'nextmo': 'Sep', 'prevmo': 'Jul'}, 
 'Sep': {'days': 30, 'nextmo': 'Oct', 'prevmo': 'Aug'},
 'Oct': {'days': 31, 'nextmo': 'Nov', 'prevmo': 'Sep'},
 'Nov': {'days': 30, 'nextmo': 'Dec', 'prevmo': 'Nov'},
 'Dec': {'days': 31, 'nextmo': 'Jan', 'prevmo': 'Jan'},}

birthdays =    {'John': ('Mar', 23, '1989'), 
'Johns_twin': ('Mar', 28, '1989'),
'Susan': ('Feb', 16, '1989'),
'Alan': ('Sep', 4, '1989'), 'Kevin': ('Dec', 23, '1989'), 'Murad': 
('Jan', 3, '1989'), 'Sandeep': ('Apr', 2, '1989'), 'James': ('Apr', 3, 
'1989'), 'Karen': ('Apr', 2, '1989'), 'Wiktoria': ('Jul', 14, '1989'), 
'Rogan': ('Jun', 29, '1989'), 'Fraser': ('Jan', 4, '1989'), 'Cameron': 
('Oct', 1, '1989')}
{'John': ('Mar', 23, '1989'), 'Johns_twin': ('Mar', 28, '1989')

Basically, if someone enters the date 'Apr' '2' I want it to return all birthdays within the range of 7 days (Mar 26 -> Apr 9)

I have most of the code working and know how to finish it, but the way I'm doing it seems extremely long. Is there a simpler solution (preferably without having to import datetime or any other modules)

The code I have thusfar from the function is as so. This is doing manual checks but to get it working for all scenarios the code will likely need to be 2-3x the length of this

def adder(bday_month_in,bday_day_in):
date_check1 = D[bday_month_in]['prevmo']
if 7 <= bday_day_in <= 21:
    max_bday = bday_day_in + 7
    min_bday = bday_day_in - 7
    print('The desired range is between', min_bday, 'and',max_bday, "of", bday_month_in)
    for key, (valX, valY, valZ) in birthdays.items():
        if valX == bday_month_in:
            if min_bday <= valY <= max_bday:
                print(key, (valX, valY, valZ))
else:
    if bday_day_in <= 6: #Apr 2
        adder = 7 - bday_day_in #5
        prev_mo = D[bday_month_in]['prevmo']  #month_max = Mar
        prev_date = D[prev_mo]['days'] - adder #days in mar (31) - 5 = 26
        print(prev_mo,prev_date)
        future_date = bday_day_in + 7
        print('The desired range is between', prev_date, "of", prev_mo,'and',future_date,bday_month_in)
        for key, (valX, valY, valZ) in birthdays.items():
            if future_date > valY and valX == bday_month_in:
                        print(key, (valX, valY, valZ))
            if valY > prev_date and valX == prev_mo:
                        print(key, (valX, valY, valZ))
    if bday_day_in => 21: #Apr 2
        adder = 7 - bday_day_in #5
        prev_mo = D[bday_month_in]['prevmo']  #month_max = Mar
        prev_date = D[prev_mo]['days'] - adder #days in mar (31) - 5 = 26
        print(prev_mo,prev_date)
        future_date = bday_day_in + 7
        print('The desired range is between', prev_date, "of", prev_mo,'and',future_date,bday_month_in)
        for key, (valX, valY, valZ) in birthdays.items():
            if future_date > valY and valX == bday_month_in:
                        print(key, (valX, valY, valZ))
            if valY > prev_date and valX == prev_mo:
                        print(key, (valX, valY, valZ))

                    #print('ValY',valY,valZ)
                   # print('prev_date',prev_date)
                  #  print('future_date',future_date)
                   # if future_date <= valY <= prev_date:

    else:
        valuer_max = days_in_that_month - 7
        month_max = D[bday_month_in]['prevmo']  # 'Mar'
        print(valuer_max,month_max)

1 个答案:

答案 0 :(得分:1)

To perform this task without a date api is not trivial as the results depend on whether a leap day (29 February) is present or not.

This also means that for a correct result, one needs to know the year we are in. For example, if the reference day is 2 March, then in a non-leap year, 23 February falls in the 7 days range, but in a leap year it falls outside of it.

You really should make use of the datetime package, and convert your dates to such datetime objects.

Here is how your code could look:

import datetime

def around(birthdays, day, maxdays):
    result = []
    for name, bday in birthdays.items():
        try:
            mappedbday = bday.replace(year=day.year)
        except ValueError: # 29 February cannot be mapped to non-leap year
            mappedbday = bday.replace(year=day.year, day=28) # Choose 28-Feb instead
        if abs((mappedbday - day).days) <= maxdays:
            result.append((name, str(mappedbday)))
    return result


# Encode birthday values as datetime objects
birthdays = {
    'John': datetime.date(1989, 3, 23), 
    'Johns_twin': datetime.date(1989, 3, 28),
    'Susan': datetime.date(1989, 2, 16),
    'Alan': datetime.date(1989, 9, 4),
    'Kevin': datetime.date(1989, 12, 23), 
    'Murad': datetime.date(1989, 1, 3), 
    'Sandeep': datetime.date(1989, 4, 2), 
    'James': datetime.date(1989, 4, 3), 
    'Karen': datetime.date(1989, 4, 2), 
    'Wiktoria': datetime.date(1989, 7, 14),
    'Rogan': datetime.date(1989, 6, 29),
    'Fraser': datetime.date(1989, 1, 4),
    'Cameron': datetime.date(1989, 10, 1)
}

# Example:
month = 'Apr'
day = 2
# Convert month's abbreviated name to month number:
monthnum = datetime.datetime.strptime(month,'%b').month
# Create a date object: we need a year, as result may differ in leap year
refdate = datetime.date(2018, monthnum, day)

print(around(birthdays, refdate, 7))

The output for the above example:

[('Johns_twin', '2018-03-28'), 
 ('Sandeep', '2018-04-02'), 
 ('James', '2018-04-03'), 
 ('Karen', '2018-04-02')]

The dates are just formatted with the str function, but you can of course choose to format them differently.

相关问题