The date is March 24, 2437 and the the Earth has been nearly completely destroyed by the actions of its inhabitants. Our last hope in this disaster lies in a shabby time machine built from old toasters and used microwave parts.  

The World Time Agency requires you to travel back in time to prevent disaster.  You are ordered to "remove" certain babies from the timeline.  

Historical newspapers and records provide the Date, Month, and Year for each mission.  Unfortunately the time machine takes input only as the number of days to travel back in time.  It is your job to calculate how many days you will need to travel back from today's date (March 24, 2437) for each mission.

For example, if a historical newspaper says a dangerous baby was born on:
Date = 21, Month = 3, Year = 2437
Then your function must compute that it was 3 Days ago.

Another example would be that a baby born on Date = 24, Month = 3, Year = 2436 would have been born 365 days ago.

You will not have time travel past the year 0.

Note that while this is a fairly simple task, it is complicated by the fact that newspapers used the Julian calendar instead of the current Gregorian calendar prior to September 14, 1752.  In 1752, it was declared that Sep 2, 1752 was proceeded immediately by September 14, 1752, entirely omitting September 3-13. Furthermore, the rules for leap years changed on that date.

After 1752, leap years are on any year divisible by four, except for years which are divisible by 100. An exception to that exception is that years divisible by 400 are always leap years.  For example, 1803, 1900, 2001, 2019, and 2100 are not leap years, but 1804, 2000 and 2020 are leap years. 
However in the Julian calander prior to and including 1752, leap years were on every year divisible by 4, without the exception of years divisible by 100.  The years 1752, 1700, 1600, and 0 were all leap years.

Good luck agent, the world depends on you!


Note: It is not required, but if you find it helpful to visualize the switch from the Julian to the Gregorian calendar, please see these links:

Please observe that much of September 1752 is missing here: https://www.timeanddate.com/calendar/?year=1752&country=1

Please observe that 1700 is a leap year here: https://www.timeanddate.com/calendar/?year=1700&country=1

Difficulty: introductory

Starter code:

def days(date, month, year):
	

Solutions:
import datetime

def days(date, month, year):
    x = datetime.datetime(year, month, date)
    y = datetime.datetime(2437, 3, 24)
    delta = y-x
    t = delta.days
    if year < 1752 or (year == 1752 and month < 9) or (year == 1752 and month == 9 and date < 14):
        t -= 11
    if year < 1752 :
        y = year //4 * 4 + 4
        for i in range(y, 1752, 4):
            if i % 100 == 0 and i % 400 != 0:
                t+=1
    return t
    


my_year = {1: 31, 2: 28, 3: 31,  4: 30,  5: 31,  6: 30, 
           7: 31, 8: 31, 9: 30, 10: 31, 11: 30, 12: 31}

def is_leap(year):
    return [0,1,0,1,0,1,1,1][(year%4==0)+(year%100==0)+(year%400==0)+4*(year < 1752)]

def day_of_year(d, m, y=2437):
    return sum(my_year[i] for i in range(1, m)) + d + is_leap(y)*(m > 2)

def days(d, m, y, d0=24, m0=3, y0=2437):
    A = day_of_year(d0, m0) # current year
    B = sum(map(is_leap, range(y+1, y0))) + 365*(y0 - y) # years between y and y0
    C = 11*(y < 1752 or y == 1752 and day_of_year(d, m) < 246) # < 03.09.1752
    D = is_leap(y) - day_of_year(d, m, y) # desired year
    return A + B - C + D

# Let's do this without the builtin date library
# and without looking up formulas in wikipedia

def is_leap_year(year):
    if year % 4 != 0:
        return False
    # year is divisible by 4.
    # If the year is in the Gregorian calendar, that's it
    if year <= 1752:
        return True
    
    # Julian calendar rule
    return (year % 100 != 0) or (year % 400 == 0)

# Day number of the first day of the month, minus one.
# Doesn't count leap years.
DOM = {
    1: 0,
    2: 31,
    3: 59,
    4: 90,
    5: 120,
    6: 151,
    7: 181,
    8: 212,
    9: 243,
    10: 273,
    11: 304,
    12: 334,
}

def is_julian_period(date, month, year):
    if year > 1752: return True
    if year < 1752: return False
    # year == 1752
    if month < 9: return False
    if month > 9: return True
    return date >= 14

# This could be rewritten as a one-liner (see wikipedia) but I'm not sure that I can derive the formula.
def normalized_day(date, month, year):
    """Number of days between given date and an arbitrary origin. normalized_day(1, 1, 0) == 1
    """
    orig_year = 0
    days = date + DOM[month] + (year - orig_year) * 365
    
    # Leap year adjustment for the current year
    if is_leap_year(year) and month >= 3:
        days += 1
    # Leap year adjustment for the intervening years
    # It could be done without a loop (count 4-year intervals,
    # subtract centuries, re-add 400-years) but it would be less
    # readable given the Gregorian stuff.
    for y in range(orig_year, year, 4):
        if is_leap_year(y):
            days += 1
    # Gregorian->Julian transition adjustment
    if is_julian_period(date, month, year):
        days -= 11
    
    return days
    
def days(date, month, year):
    return normalized_day(24, 3, 2437) - normalized_day(date, month, year)

def days(date, month, year):
   
    ## create function to calculate day value
    def day_calc(date, month, year):
        count = 0
        
        #find days in years
        for i in range (0,year):
            if i < 1752:
                if i % 4 == 0:
                    count += 366
                else:
                    count += 365
            elif i == 1752:
                count += 366-11
            else:
                if i % 400 == 0:
                    count += 366
                elif i % 100 == 0:
                    count += 365
                elif i % 4 == 0:
                    count += 366
                else:
                    count += 365
         
        #dictionary of days passed at a month end
        months = {0:0,1:31,2:59,3:90,4:120,5:151,6:181,7:212,8:243,9:273,10:304,11:334,12:365}
        
        #find days in month
        if year % 400 == 0:
            count += months[month-1]
            if month > 2:
                count += 1
        elif year % 100 == 0:
            count += months[month-1]
        elif year % 4 == 0:
            count += months[month-1]
            if month > 2:
                count += 1
        else:
            count += months[month-1]
         
        #add days in month, check if it was in Sept 1752 when 11 days were skipped
        if year == 1752 and month == 9 and date > 13:
            count += date -11
        else:
            count += date
       
        return count
    
    cdate = 24
    cmonth = 3
    cyear = 2437
    
    return day_calc(cdate, cmonth, cyear) - day_calc(date, month, year)
    

    
print(days(31,1,2436))    

from datetime import *

def julian(day,month,year):
    dayy=(year-1)*365+(year-1)//4
    daym=sum([0,31,29 if year%4==0 else 28,31,30,31,30,31,31,30,31,30,31][:month])
    return dayy+daym+day

ref =date(2437,3,24)
greg=date(1752,9,14)
days2greg=(ref-greg).days
jgreg=julian(3,9,1752)

def days(day, month, year):
    if year>1752 or (year==1752 and month>9) or (year==1752 and month==9 and day>13):
        return (ref-date(year,month,day)).days
    else:
      return jgreg-julian(day,month,year)+days2greg
      


def days(date, month, year):
    current_year = 2437
    current_month = 3
    current_date = 24
    current_days = (24+28+31)
    days = 0
    y_days = 0
    
    print((date,month,year))
    
    def leap_year(year):
        condition = False
        if year > 1752:
            if year % 400 == 0:
                condition = True
            elif year % 100 == 0:
                condition = False
            elif year % 4 == 0:
                condition = True
        else:
            if year % 4 == 0:
                condition = True
        return condition
    
    month_30 = {1:31,2:28,3:31,4:30,5:31,6:30,7:31,8:31,9:30,10:31,11:30,12:31}
    month_30_leap = {1:31,2:29,3:31,4:30,5:31,6:30,7:31,8:31,9:30,10:31,11:30,12:31}
    
    if year > 1752:
        if leap_year(year) == True: #if its a leap year
            for m in range(1,month):
                days += month_30_leap[m]
            days += date
            for y in range(year, current_year):
                if leap_year(y) == True:
                    y_days += 366
                else:
                    y_days += 365
            days = current_days - days + y_days
            print("this one - 1")
            return days
        else:
            for m in range(1,month):
                days += month_30[m]
            days += date
            for y in range(year, current_year):
                if leap_year(y) == True:
                    y_days += 366
                else:
                    y_days += 365
            days = current_days - days + y_days
            print("this one = 2")
            return days
    else:
        if year % 4 == 0:
        
            for m in range(1,month):
                days += month_30_leap[m]
                
            if year == 1752 and month > 9:
                days -= 11
                    
            if year == 1752 and month == 9:
            
                for d in range(1,date+1):
                    if 3 > d or d > 13:
                        print(d)
                        days += 1
            else:
                days += date
                
            for y in range(year, current_year):
                if leap_year(y) == True:
                    if y == 1752:
                        y_days += 366-11
                    else:
                        y_days += 366
                else:
                    y_days += 365
            days = current_days - days + y_days
            print("this one - 3")
            return days
            
        else:
            for m in range(1,month):
                days += month_30[m]

            days += date
                
            for y in range(year, current_year):
                if leap_year(y) == True:
                    if y == 1752:
                        y_days += 366-11
                    else:
                        y_days += 366
                else:
                    y_days += 365
            days = current_days - days + y_days
            print("this one - 4")
            return days
          


def leap(year):
    if year < 1753:
        if year % 4 == 0:
            return True
    else:
        if year % 4 == 0:
            if year % 100 != 0 or year % 400 == 0:
                return True
            elif year % 100 == 0:
                return False
        else:
            return False

def days(date, month, year):
    the_date = [24, 3, 2437]

    Leap_year = {1: 31, 2: 29, 3: 31, 4: 30, 5: 31, 6: 30, 7: 31,
                 8: 31, 9: 30, 10: 31, 11: 30, 12: 31}
    Non_leap_year = {1: 31, 2: 28, 3: 31, 4: 30, 5: 31, 6: 30, 7: 31,
                     8: 31, 9: 30, 10: 31, 11: 30, 12: 31}

    point_date = [date, month, year]
    reverse_date = [year, month, date]

    days_from_beginning = the_date[0]
    for i in range(1, the_date[1]):
        days_from_beginning += Non_leap_year[i]

    def to_year_end(list, dict):
        days_to_end = dict[list[1]] - list[0]
        for i in range(list[1] + 1, 13):
            days_to_end += dict[i]
        return days_to_end

    if year == the_date[2] and month == the_date[1]:
        result = the_date[0] - date
        return result
    
    elif year == the_date[2] and month < the_date[1]:
        result = days_from_beginning - date
        for i in range(1, month):
            result -= Non_leap_year[i]
        return result

    else:
        result = days_from_beginning
        if reverse_date < [1752, 9, 14]:
            result -= 11
        if leap(year):
            result += to_year_end(point_date, Leap_year)
        else:
            result += to_year_end(point_date, Non_leap_year)
        for y in range(year + 1, the_date[2]):
            if leap(y):
                result += 366
            else:
                result += 365
        return result

def days(date, month, year):
    
    def leap_year(y):
        if y % 4 == 0:
            if y>1752 and y%100==0: 
                if y%400==0:
                    return True
                else:
                    return False
            return True
            
    def days_in_years(y):
        n=0
        for num in range(1,y):
            if leap_year(num):
                n+=1
        return ((y-1)*365+n) if y<=1752  else ((y-2)*365+n+354)
    

    def days_in_month(m,y):
        n=0
        list_31 = [1,3,5,7,8,10,12]
        list_30 = [4,6,9,11]
        for num in range(1,m):
            if num in list_31:
                n+=31
            elif num in list_30:
                n+=30
            elif leap_year(y):
                n+=29
            else:
                n+=28
        if y == 1752 and m > 9:
            n-=11
        return n
        
    def days_in_days(d,m,y):
        if y==1752 and m==9 and d>2:
            return d-11
        return d
    
    current_days = days_in_days(24,3,2437)+days_in_month(3,2437)+days_in_years(2437)
    return current_days - (days_in_days(date,month,year) + days_in_month(month,year)+days_in_years(year) )


def days(date, month, year):
    daysaway = 0
    monthdays = 0
    leapyear = 0
    monthsinyear = [31,28,31,30,31,30,31,31,30,31,30,31] 

    daysaway += 24- date

    if year < 2437:
        daysaway += (2437 - year) * 365

    if month < 3:
        if month == 1:
            daysaway += monthsinyear[0] + monthsinyear[1]
        else:
            daysaway += monthsinyear[1] 
    elif month > 3:
        for i in range(3,month):
            monthdays -= monthsinyear[i-1]
        daysaway += monthdays

    if year < 1752 or (year == 1752 and month < 9) or (year == 1752 and month == 9 and date < 3):
        daysaway -= 11

    for i in range(year,2438):
        if i <= 1752 and i % 4 == 0:
            leapyear += 1
            if i==year and month > 2:
                leapyear -=1
        elif i > 1752:
            if i % 400 == 0 or (i % 4 == 0 and i % 100 !=  0):
                leapyear += 1
                if i==year and month > 2:
                    leapyear -=1
    daysaway += leapyear
    
    return daysaway

from datetime import date

'''Datetime assumes "the current Gregorian calendar always 
   was, and always will be, in effect."'''
GREG_START = date(1752, 9, 14)
GREG_SKIP = 11
CURR_DATE = date(2437, 3, 24)

def days(day, month, year):
    try:
        target_date = date(year, month, day)
        distance = (CURR_DATE - target_date).days
    except ValueError:  # Gregorian/Julian conflict
        target_date = date(year, month, day-1)
        distance = (CURR_DATE - target_date).days - 1
    if target_date < GREG_START:
        distance -= GREG_SKIP
        distance += len([cent for cent in range((year-1)//100 + 1, GREG_START.year//100 + 1) if cent % 4])
    return distance