Days old udacity - python

I have a problem in these two casesprint daysBetweenDates(2011, 1, 1, 2012, 8, 8)
print daysBetweenDates(1900,1,1, 1999,12, 31)when I put them with the other test cases I got a wrong answer by 1 day extra and sometimes by 2 days.sometimes one of them give me the right answer but it also appears asTest with data:(2011, 1, 1, 2012,8,8)failed
Test with data: (1900, 1, 1, 1999, 12, 31) failed but when I test each case alone i got the right answer.
daysofmonths = [ 0,31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
def leap_year(year):
leap_day = 366
common_day = 365
if year % 4 != 0:
return common_day
elif year % 100 != 0:
return leap_day
elif year % 400 !=0:
return common_day
else:
return leap_day
def daysBetweenDates(year1, month1, day1, year2, month2, day2):
#code for same year
if year1 == year2:
if month1 == month2:
return day2 - day1
days = daysofmonths[month1] - day1
month1 = month1 + 1
while month1 < month2:
if leap_year(year1) == 366:
daysofmonths[2] = 29
days = days + daysofmonths[month1]
month1 = month1 + 1
return days + day2
################################################
days = daysofmonths[month1] - day1
month1 = month1 + 1
while month1 <= 12:
if leap_year(year1) == 366:
daysofmonths[2] = 29
days = days + daysofmonths[month1]
month1 = month1 + 1
#print days
year1 = year1 + 1
###########################################################
days = days + day2
month2 = month2 - 1
while month2 >= 1:
if leap_year(year2) == 366:
daysofmonths[2] = 29
days = days + daysofmonths[month2]
month2 = month2 - 1
#print days
year2 = year2 - 1
###########################################################
while year1 <= year2:
days = days + leap_year(year1)
year1 = year1 + 1
return days
print daysBetweenDates(2011, 1, 1, 2012, 8, 8)
print daysBetweenDates(1900,1,1, 1999,12, 31)
def test():
test_cases = [((2012,1,1,2012,2,28), 58),
((2012,1,1,2012,3,1), 60),
((2011,6,30,2012,6,30), 366),
((2011,1,1,2012,8,8), 585 ),
((1900,1,1,1999,12,31), 36523)]
for (args, answer) in test_cases:
result = daysBetweenDates(*args)
if result != answer:
print "Test with data:", args, "failed"
else:
print "Test case passed!"
test()

when you do:
daysofmonths[2] = 29
it changes the element in the list, which then is used for every subsequent call, if you added print(daysofmonths[2]) in between the test cases you would see that it is always 29 after the first case that needs to check February, so instead of conditionally changing the list with:
if leap_year(year1) == 366:
daysofmonths[2] = 29
days = days + daysofmonths[month1]
just conditionally add to days:
if leap_year(year1) == 366 and month1 == 2:
days = days + 29
else:
days = days + daysofmonths[month1]
then do the same thing lower down with year2 and month2 (I would highly recommend you separate your code into more functions as a lot of it is very repetitive)

This is the only post I found here on this particular problem so I thought I would share my solution.
#days in the months of a non leap year
daysOfMonths = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
#determine if a year is a leap year
def is_leap_year(year1):
year = True
if year1 % 4 != 0:
year = False
elif year1 % 100 != 0:
year = True
elif year1 % 400 != 0:
year = False
else: year = True
return year
#returns the days in the given month of the given year
#I was trying to do something similar to the OP until I read this post
def days_in_month(year, month):
days = 0
if is_leap_year(year) and month == 2:
days += 29
else:
days += daysOfMonths[month - 1]
return days
#itterates through each month starting at year1 month1
#up to but not including month2 of year2 and
#returns the total number of days in that period
def total_days(year1, month1, year2, month2):
days = 0
while year1 < year2 or month1 < month2:
days += days_in_month(year1, month1)
month1 += 1
if month1 == 13:
year1 += 1
month1 = 1
return days
def daysBetweenDates(year1, month1, day1, year2, month2, day2):
days = total_days(year1, month1, year2, month2)
#because I included the beginning month I have to subtract day1
#because I did not include the final month I have to add day2
return days - day1 + day2
#I used print statements here to troubleshoot
#print days_in_month(2012, 1)
#print daysBetweenDates(2012, 1, 1, 2012, 2, 28)
#print daysBetweenDates(2012, 1, 1, 2012, 3, 1)
#print daysBetweenDates(2011,6,30,2012,6,30)
#print daysBetweenDates(2011,1,1,2012,8,8)
#print daysBetweenDates(1900,1,1,1999,12,31)
def test():
test_cases = [((2012,1,1,2012,2,28), 58),
((2012,1,1,2012,3,1), 60),
((2011,6,30,2012,6,30), 366),
((2011,1,1,2012,8,8), 585 ),
((1900,1,1,1999,12,31), 36523)]
for (args, answer) in test_cases:
result = daysBetweenDates(*args)
if result != answer:
print "Test with data:", args, "failed"
else:
print "Test case passed!"
test()

Related

Python - Basic Leap year function problem (Novice)

So basically my problem is, I have a list from 2020 to 2030 and my program said every year is a leap year.
My variables are:
yearList = [2020, 2021, 2022, 2023, 2024, 2025, 2026, 2027, 2028, 2029, 2030]
monthList = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]
daysOfMonth = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
def create_calendar(yearList: list, monthList: list, daysOfMonth: list, numbOfShootingStars: int):
calendar = {}
for year in yearList:
# Create year
calendar[year] = {}
for month in monthList:
# If the list don't have 12 months, it won't loop through all months
if month == 12 and month + 1 == 1: break;
else:
# Create monthly data
calendar[year][month] = {}
# If February is a leap year, it will have 29 days instead of 28
if month == 2 and year % 4 == 0:
daysOfMonth[month - 1] = 29
# Create the days and daily data
for day in range(1, daysOfMonth[monthList.index(month)] + 1):
calendar[year][month][day] = numbOfShootingStars
return calendar
Thank you for your help!
1 question, is it possible to use a list like this for this method?
monthList = [
{1, 'January'},
{2, 'February'},
{3, 'March'},
{4, 'April'},
{5, 'May'},
{6, 'June'},
{7, 'July'},
{8, 'August'},
{9, 'September'},
{10, 'October'},
{11, 'November'},
{12, 'December'}]
Then how should I modify my code because I couldn't get it work :(
Okay, I think I solved it, the problem was, I changed to value in the daysOfMonth list at February to 29 and then it stays like that. With this if - else I changed back to it's original state when it is not a leap year.
# If February is a leap year, it will have 29 days instead of 28
if month == 2 and year % 4 == 0:
daysOfMonth[month - 1] = 29
else:
daysOfMonth[month - 1] = 28
If you take a year to be 365.2425 days, this is 365 + 1/4 - 1/100 + 1/400. This explains why in the long run you stick to the correct value by adding a whole day every fourth year, but not on every century, but on every fourth century (starting from 0).
A possible implementation is, to tell if the year Y is leap:
Floor(365.2425 Y) - Floor(365.2425 (Y-1)) - 365

Parsing dates and I am lost

Write a program to read dates from input, one date per line. Each date's format must be as follows: March 1, 1990. Any date not following that format is incorrect and should be ignored. The input ends with -1 on a line alone. Output each correct date as: 3/1/1990.
Hint: Use string[start:end] to get a substring when parsing the string and extracting the date. Use the split() method to break the input into tokens.
Ex: If the input is:
March 1, 1990
April 2 1995
7/15/20
December 13, 2003
-1
then the output is:
3/1/1990
12/13/2003
This is what I have to start with and I am lost. Help?
def get_month_as_int(monthString):
if monthString == 'January':
month_int = 1
elif monthString == 'February':
month_int = 2
elif monthString == 'March':
month_int = 3
elif monthString == 'April':
month_int = 4
elif monthString == 'May':
month_int = 5
elif monthString == 'June':
month_int = 6
elif monthString == 'July':
month_int = 7
elif monthString == 'August':
month_int = 8
elif monthString == 'September':
month_int = 9
elif monthString == 'October':
month_int = 10
elif monthString == 'November':
month_int = 11
elif monthString == 'December':
month_int = 12
else:
month_int = 0
return month_int
user_string = input()
# TODO: Read dates from input, parse the dates to find the one
# in the correct format, and output in m/d/yyyy format
import datetime
inputs = []
result = []
#read the inputs
date = input()
inputs.append(date)
while not date == "-1":
date = input()
inputs.append(date)
#check if the input is in the correct format and convert it.
for date_text in inputs:
try:
date_text = datetime.datetime.strptime(date_text,"%d %B, %Y")
result.append(date_text.strftime("%d/%m/%Y"))
except ValueError:
pass
print(*result, sep = "\n")
s=0
d={'january':1,
'february':2,
'march':3,
'april':4,
'may':5,
'june':6,
'july':7,
'august':8,
'september':9,
'october':10,
'november':11,
'december':12}
while s!='-1':
s=input()
if "," in s:
s = s.split(",")
ar = s[0].split(" ")
if len(ar)<2:
continue
month, date = ar[0], ar[1]
year = s[1].strip()
if d.get(month.lower()):
print("{}/{}/{}".format(date, d[month.lower()], year))

Calculate the next and the 3rd business date from a given date

I am trying to implement a function to calculate the next and 3rd business day from a given date (ideally taking into account some given holidays)
def day_of_week(year, month, day):
t = [0, 3, 2, 5, 0, 3, 5, 1, 4, 6, 2, 4]
year -= month < 3
return (year + int(year/4) - int(year/100) + int(year/400) + t[month-1] + day) % 7
The input is in the format YYYYMMDD with 21th of March 2018 written as 20180321 and the output date should be in the same format.
I`m trying to do something like this but I realised this is not the best practice
def leap_year(year):
if(year%4==0 and year%100!=0):
return True
elif (year%4==0 and year%100==0 and year%400==0):
return True
else:
return False
def business_day(year, month, day):
if (month==12):
if(day_of_week(year, month, day)<5 and day_of_week(year, month, day)>0 and day==31):
return str(year+1)+str(0)+str(1)+str(0)+str(1)
elif (day_of_week(year, month, day)<5 and day_of_week(year, month, day)>0 and day!=31):
newDay="0"
if(day<10):
newDay = newDay + str(day+1)
else:
newDay = str(day+1)
return str(year) + str(month) + newDay
elif (day_of_week(year, month, day)>=5 and day==31):
if(day_of_week(year, month, day)==5):
return str(year+1)+"01"+"03"
if (day_of_week(year, month, day) == 6):
return str(year + 1) + "01" + "02"
if (day_of_week(year, month, day) == 0):
return str(year + 1) + "01" + "01"
elif (day_of_week(year, month, day)>=5 and day==30):
if((day_of_week(year, month, day)==5)):
return str(year + 1) + "01" + "02"
if ((day_of_week(year, month, day) == 6)):
return str(year + 1) + "01" + "01"
if ((day_of_week(year, month, day) == 0)):
return str(year + 1) + str(month) + str(day+1)
Can`t use any libraries in the solution. Thanks for the help
No libraries! I had some fun learning Python. Did you? :-)
def day_of_week(year, month, day):
t = [0, 3, 2, 5, 0, 3, 5, 1, 4, 6, 2, 4]
year -= month < 3
dw = (year + year // 4 - year // 100 + year // 400 + t[month-1] + day) % 7
return [6, 0, 1, 2, 3, 4, 5][dw] # To be consistent with 'datetime' library
def leap_year(year):
leap = year % 4 == 0 and (year % 100 != 0 or year % 400 == 0)
return True if leap else False
def valid_day(year, month, day):
month_list = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
if year < 1 or year > 9999 or month < 1 or month > 12:
return False
m = month_list[month-1] if month != 2 or not leap_year(year) else 29
return True if 1 <= day <= m else False
class Career(Exception):
def __str__(self): return 'So I became a waiter...'
MAX_DATE_AND_DAYS_INT = 365 * 100
class Date:
# raise ValueError
def __init__(self, year, month, day):
if not valid_day(year, month, day):
raise Career()
self.y, self.m, self.d = year, month, day
#classmethod
def fromstring(cls, s):
s1, s2, s3 = int(s[0:4]), int(s[4:6]), int(s[6:8])
return cls(s1, s2, s3)
def __repr__(self) -> str:
return '%04d%02d%02d' % (self.y, self.m, self.d)
def weekday_date(self) -> str:
names = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
return names[self.weekday()] + ' ' + str(self)
def next_day(self):
if valid_day(self.y, self.m, self.d + 1):
return Date(self.y, self.m, self.d + 1)
elif valid_day(self.y, self.m + 1, 1):
return Date(self.y, self.m + 1, 1)
elif valid_day(self.y + 1, 1, 1):
return Date(self.y + 1, 1, 1)
else:
raise Career
def weekday(self):
return day_of_week(self.y, self.m, self.d)
def __add__(self, other):
"Add a Date to an int."
if isinstance(other, int):
if other < 1 or other > MAX_DATE_AND_DAYS_INT:
raise OverflowError("int > MAX_DATE_AND_DAYS_INT")
new_date = Date(self.y, self.m, self.d)
while other >= 1:
new_date = new_date.next_day()
other -= 1
return new_date
return NotImplemented
def next_working_day(self):
day = self.next_day()
while True:
while day.weekday() >= 5:
day = day.next_day()
holidays_list = year_holidays(day.y)
for str_day in holidays_list:
s2 = str(day)
if str_day == s2:
day = day.next_day()
break # for
if day.weekday() < 5:
break # while True
return day
def year_holidays(year):
holidays = [
["New Year's Day", 1, 1], # Fixed: January 1
["Birthday of Martin Luther King, Jr.", 1, 0, 0, 3], # Floating
["Washington's Birthday", 2, 0, 0, 3], # Third Monday in February
["Memorial Day", 5, 0, 0, 5], # Last Monday
["Independence Day", 7, 4],
["Labor Day", 9, 0, 0, 1],
["Columbus Day", 10, 0, 0, 2],
["Veterans Day", 11, 11],
["Thanksgiving Day", 11, 0, 3, 4],
["Christmas Day", 12, 25]
]
year_list = []
for h in holidays:
if h[2] > 0:
day = Date(year, h[1], h[2]) # Fixed day
else:
day = Date(year, h[1], 1) # Floating day
while h[3] != day.weekday(): # Advance to match the weekday
day = day.next_day()
count = 1
while count != h[4]: # Match the repetition of this day
next_week = day + 7
if next_week.m == day.m:
day = next_week
count += 1
year_list.append(str(day))
return year_list # return the holidays as list of strings
if __name__ == '__main__':
dates = [
['20190308', '20190311', '20190313'],
['20190309', '20190311', '20190313'],
['20190310', '20190311', '20190313'],
['20190311', '20190312', '20190314'],
['20190329', '20190401', '20190403'],
['20181231', '20190102', '20190104'],
['20190118', '20190122', '20190124'],
['20190216', '20190219', '20190221'],
['20190526', '20190528', '20190530'],
['20190703', '20190705', '20190709'],
['20190828', '20190829', '20190903'],
['20191010', '20191011', '20191016'],
['20191108', '20191112', '20191114'],
['20191125', '20191126', '20191129'],
['20191224', '20191226', '20191230'],
['20191227', '20191230', '20200102']]
print('\n Today Next and 3rd business day')
for days in dates:
today = Date.fromstring(days[0])
next_day = today.next_working_day()
third_day = next_day.next_working_day().next_working_day()
if str(next_day) != days[1] or str(third_day) != days[2]:
print('*** ERROR *** ', end='')
else:
print(' ', end='')
print(today.weekday_date(), next_day.weekday_date(), third_day.weekday_date())
Output:
Today Next and 3rd business day
Fri 20190308 Mon 20190311 Wed 20190313
Sat 20190309 Mon 20190311 Wed 20190313
Sun 20190310 Mon 20190311 Wed 20190313
Mon 20190311 Tue 20190312 Thu 20190314
Fri 20190329 Mon 20190401 Wed 20190403
Mon 20181231 Wed 20190102 Fri 20190104
Fri 20190118 Tue 20190122 Thu 20190124
Sat 20190216 Tue 20190219 Thu 20190221
Sun 20190526 Tue 20190528 Thu 20190530
Wed 20190703 Fri 20190705 Tue 20190709
Wed 20190828 Thu 20190829 Tue 20190903
Thu 20191010 Fri 20191011 Wed 20191016
Fri 20191108 Tue 20191112 Thu 20191114
Mon 20191125 Tue 20191126 Fri 20191129
Tue 20191224 Thu 20191226 Mon 20191230
Fri 20191227 Mon 20191230 Thu 20200102
import datetime
example = '20180321'
# you can parse the time string directly to a datetime object
next_buisness_day = datetime.datetime.strptime(example, '%Y%m%d')
# specify the increment based on the day of the week or any
#other condition
increment = 1
print('day day is', next_buisness_day.weekday())
# if friday
if next_buisness_day.weekday() == 4:
increment = 3
# if saturday
elif next_buisness_day.weekday() == 5:
increment = 2
next_buisness_day += datetime.timedelta(days=increment)
# and convert back to whatever format you like
print('{:%Y%m%d}'.format(next_buisness_day))
Have a look at the datetime module you can do all sorts of things with it.
https://docs.python.org/3/library/datetime.html
I use few functions from 'datetime' library. You can have fun to write them: date(y, m, d), timedelta(days=7), day,weekday(), '{:%Y%m%d}'.format(day), strptime(input, '%Y%m%d'), strftime(datetime, '%a %x'). Good idea is to create a class for date and get rid from all format conversions. So, only date(y, m, d), timedelta(days=7), day, weekday() will be left for exercise.
import datetime
from datetime import date, timedelta
def day2string(day):
return '{:%Y%m%d}'.format(day)
def year_holidays(year):
holidays = [
["New Year's Day", 1, 1], # Fixed: January 1
["Birthday of Martin Luther King, Jr.", 1, 0, 0, 3], # Floating
["Washington's Birthday", 2, 0, 0, 3], # Third Monday in February
["Memorial Day", 5, 0, 0, 5], # Last Monday
["Independence Day", 7, 4],
["Labor Day", 9, 0, 0, 1],
["Columbus Day", 10, 0, 0, 2],
["Veterans Day", 11, 11],
["Thanksgiving Day", 11, 0, 3, 4],
["Christmas Day", 12, 25]
]
year_list = []
for h in holidays:
if h[2] > 0:
day = date(year, h[1], h[2]) # Fixed day
else:
day = date(year, h[1], 1) # Floating day
while h[3] != day.weekday(): # Advance to match the weekday
day += timedelta(days=1)
count = 1
while count != h[4]: # Match the repetition of this day
next_week = day + timedelta(days=7)
if next_week.month == day.month:
day = next_week
count += 1
year_list.append(day2string(day))
return year_list # return the holidays as list of strings
def str2datetime(string):
return datetime.datetime.strptime(string, '%Y%m%d')
def next_working_day(string):
day = str2datetime(string)
day += timedelta(days=1)
while True:
while day.weekday() >= 5:
day += timedelta(days=1)
holidays_list = year_holidays(day.year)
for str_day in holidays_list:
s2 = day2string(day)
if str_day == s2:
day += timedelta(days=1)
break # for
if day.weekday() < 5:
break # while True
return day2string(day)
if __name__ == '__main__':
dates = [
['20190308', '20190311', '20190313'],
['20190309', '20190311', '20190313'],
['20190310', '20190311', '20190313'],
['20190311', '20190312', '20190314'],
['20190329', '20190401', '20190403'],
['20181231', '20190102', '20190104'],
['20190118', '20190122', '20190124'],
['20190216', '20190219', '20190221'],
['20190526', '20190528', '20190530'],
['20190703', '20190705', '20190709'],
['20190828', '20190829', '20190903'],
['20191010', '20191011', '20191016'],
['20191108', '20191112', '20191114'],
['20191125', '20191126', '20191129'],
['20191224', '20191226', '20191230'],
['20191227', '20191230', '20200102']]
print('\n Today Next and 3rd business day')
for days in dates:
next_day = next_working_day(days[0])
third_day = next_working_day(next_working_day(next_day))
if next_day != days[1] or third_day != days[2]:
print('*** ERROR *** ', end='')
else:
print(' ', end='')
def f(x): return datetime.datetime.strftime(str2datetime(x), '%a %x')
print(f(days[0]), f(next_day), f(third_day))
It should create the next output:
Today Next and 3rd business day
Fri 03/08/19 Mon 03/11/19 Wed 03/13/19
Sat 03/09/19 Mon 03/11/19 Wed 03/13/19
Sun 03/10/19 Mon 03/11/19 Wed 03/13/19
Mon 03/11/19 Tue 03/12/19 Thu 03/14/19
Fri 03/29/19 Mon 04/01/19 Wed 04/03/19
Mon 12/31/18 Wed 01/02/19 Fri 01/04/19
Fri 01/18/19 Tue 01/22/19 Thu 01/24/19
Sat 02/16/19 Tue 02/19/19 Thu 02/21/19
Sun 05/26/19 Tue 05/28/19 Thu 05/30/19
Wed 07/03/19 Fri 07/05/19 Tue 07/09/19
Wed 08/28/19 Thu 08/29/19 Tue 09/03/19
Thu 10/10/19 Fri 10/11/19 Wed 10/16/19
Fri 11/08/19 Tue 11/12/19 Thu 11/14/19
Mon 11/25/19 Tue 11/26/19 Fri 11/29/19
Tue 12/24/19 Thu 12/26/19 Mon 12/30/19
Fri 12/27/19 Mon 12/30/19 Thu 01/02/20

Udacity's finish daysBetweenDates answer might be wrong

There might be a bug in this lesson.
I'm trying to move forward without needing to watch the answer videos for the daysBetweenDates quiz.
Long story short:
I figured out the code and it works for all test cases, except one.
The error was odd. The difference between the number of days between dates I got and the answer according to Udacity. My notion is that if there's error in my code, the difference between the answer I got and Udacity's expected answer would be more than 1 because the error should be recurring.
I tried to compute the number of days between dates using a different approach. I got the number my program computed.
So the question is, is the number of days between dates between 1900,1 ,1 and 1999,12, 31 really 36523(Udacity's answer) or 36524(my answer)
Here's my complete code
I recommend you try it on your interpreter to check if Udacity's answer for the last test case is correct.
# Credit goes to Websten from forums
#
# Use Dave's suggestions to finish your daysBetweenDates
# procedure. It will need to take into account leap years
# in addition to the correct number of days in each month.
number_of_days_in_month = 30
def nextDay(year, month, day):
"""Simple version: assume every month has 30 days"""
number_of_days_in_month = setDaysInMonth(month, year)
if day < number_of_days_in_month:
return year, month, day + 1
else:
if month == 12:
return year + 1, 1, 1
else:
return year, month + 1, 1
def dateIsBefore(year1, month1, day1, year2, month2, day2):
"""Returns True if year1-month1-day1 is before year2-month2-day2. Otherwise, returns False."""
if year1 < year2:
return True
if year1 == year2:
if month1 < month2:
return True
if month1 == month2:
return day1 < day2
return False
def daysBetweenDates(year1, month1, day1, year2, month2, day2):
"""Returns the number of days between year1/month1/day1
and year2/month2/day2. Assumes inputs are valid dates
in Gregorian calendar."""
# program defensively! Add an assertion if the input is not valid!
assert not dateIsBefore(year2, month2, day2, year1, month1, day1)
number_of_days_between_dates = 0
while dateIsBefore(year1, month1, day1, year2, month2, day2):
year1, month1, day1 = nextDay(year1, month1, day1)
number_of_days_between_dates += 1
print number_of_days_between_dates
return number_of_days_between_dates
def setDaysInMonth(month1, year1):
if isLeapYear(year1) == False:
if month1 == 1:
number_of_days_in_month = 31
if month1 == 3:
number_of_days_in_month = 31
if month1 == 5:
number_of_days_in_month = 31
if month1 == 7:
number_of_days_in_month = 31
if month1 == 8:
number_of_days_in_month = 31
if month1 == 10:
number_of_days_in_month = 31
if month1 == 12:
number_of_days_in_month = 31
if month1 == 4:
number_of_days_in_month = 30
if month1 == 6:
number_of_days_in_month = 30
if month1 == 9:
number_of_days_in_month = 30
if month1 == 11:
number_of_days_in_month = 30
if month1 == 2:
number_of_days_in_month = 28
return number_of_days_in_month
else:
if month1 == 1:
number_of_days_in_month = 31
if month1 == 3:
number_of_days_in_month = 31
if month1 == 5:
number_of_days_in_month = 31
if month1 == 7:
number_of_days_in_month = 31
if month1 == 8:
number_of_days_in_month = 31
if month1 == 10:
number_of_days_in_month = 31
if month1 == 12:
number_of_days_in_month = 31
if month1 == 4:
number_of_days_in_month = 30
if month1 == 6:
number_of_days_in_month = 30
if month1 == 9:
number_of_days_in_month = 30
if month1 == 11:
number_of_days_in_month = 30
if month1 == 2:
number_of_days_in_month = 29
return number_of_days_in_month
def isLeapYear(year1):
if year1 % 4 == 0:
return True
return False
def numberOfLeapYears(year1, year2):
number_of_leap_years = 0
while year1 < year2:
if year1 % 4 == 0:
number_of_leap_years += 1
year1 += 1
else:
year1 += 1
#print "number of leap years: " + str(number_of_leap_years)
return number_of_leap_years
def numberOfNonLeapYears(year1, year2):
number_of_non_leap_years = 0
while year1 < year2:
if year1 % 4 == 0:
year1 += 1
else:
number_of_non_leap_years += 1
year1 += 1
#print "number of non leap years: " + str(number_of_non_leap_years)
return number_of_non_leap_years
def numberOfDays(year1, year2):
number_of_leap_years = numberOfLeapYears(year1, year2)
print number_of_leap_years
number_of_non_leap_years = numberOfNonLeapYears(year1, year2)
print number_of_non_leap_years
number_of_days = 0
number_of_days = number_of_leap_years * 366 + number_of_non_leap_years * 365
#print number_of_days
return number_of_days
def test():
test_cases = [((2012,1,1,2012,2,28), 58),
((2012,1,1,2012,3,1), 60),
((2011,6,30,2012,6,30), 366),
((2011,1,1,2012,8,8), 585 ),
((1900,1,1,1999,12,31), 36523),
((1900,1,1,1910,1,1), 3653)]
for (args, answer) in test_cases:
result = daysBetweenDates(*args)
if result != answer:
print "Test with data:", args, "failed"
else:
print "Test case passed!"
test()
#print isLeapYear(1900)
#print 366*3 + 365*7
#print numberOfLeapYears(1900, 1999)
#print numberOfNonLeapYears(1900, 1999)
print numberOfDays(1900, 2000)
You are using a naive test for Leap Year ( %4). But there are additional rules to leap years.
Leap year is any year evenly divisible by 4, unless it is divisible by 100 (then it is not a leap year), unless it is divisible by 400 (Then it is a leap year).
Thus 1500, 1700, 1800, 1900 were not leaps years but 1600 and 2000 were leap years.
A simple Python version:
def is_leap_year(year):
if year % 400 == 0:
return True
if year % 4 == 0 and not year % 100 == 0:
return True
return False

How to assign months to their numeric equivalents in Python / Pandas?

Currently, I'm using the following for loop based on an if condition for each month to assign months to their numeric equivalents. It seems to be quite efficient in terms of runtime, but is too manual and ugly for my preferences.
How could this be better executed? I imagine it's possible to improve on it by simplifying/condensing the multiple if conditions somehow, as well as by using some sort of translator that is made for date conversions? Each of which would be preferable?
#make numeric month
combined = combined.sort_values('month')
combined.index = range(len(combined))
combined['month_numeric'] = None
for i in combined['month'].unique():
first = combined['month'].searchsorted(i, side='left')
last = combined['month'].searchsorted(i, side='right')
first_num = list(first)[0] #gives first instance
last_num = list(last)[0] #gives last instance
if i == 'January':
combined['month_numeric'][first_num:last_num] = "01"
elif i == 'February':
combined['month_numeric'][first_num:last_num] = "02"
elif i == 'March':
combined['month_numeric'][first_num:last_num] = "03"
elif i == 'April':
combined['month_numeric'][first_num:last_num] = "04"
elif i == 'May':
combined['month_numeric'][first_num:last_num] = "05"
elif i == 'June':
combined['month_numeric'][first_num:last_num] = "06"
elif i == 'July':
combined['month_numeric'][first_num:last_num] = "07"
elif i == 'August':
combined['month_numeric'][first_num:last_num] = "08"
elif i == 'September':
combined['month_numeric'][first_num:last_num] = "09"
elif i == 'October':
combined['month_numeric'][first_num:last_num] = "10"
elif i == 'November':
combined['month_numeric'][first_num:last_num] = "11"
elif i == 'December':
combined['month_numeric'][first_num:last_num] = "12"
You can use to_datetime, then month, convert to string and use zfill:
print (pd.to_datetime(df['month'], format='%B').dt.month.astype(str).str.zfill(2))
Sample:
import pandas as pd
df = pd.DataFrame({ 'month': ['January','February', 'December']})
print (df)
month
0 January
1 February
2 December
print (pd.to_datetime(df['month'], format='%B').dt.month.astype(str).str.zfill(2))
0 01
1 02
2 12
Name: month, dtype: object
Another solution is map by dict d:
d = {'January':'01','February':'02','December':'12'}
print (df['month'].map(d))
0 01
1 02
2 12
Name: month, dtype: object
Timings:
df = pd.DataFrame({ 'month': ['January','February', 'December']})
print (df)
df = pd.concat([df]*1000).reset_index(drop=True)
print (pd.to_datetime(df['month'], format='%B').dt.month.astype(str).str.zfill(2))
print (df['month'].map({'January':'01','February':'02','December':'12'}))
In [200]: %timeit (pd.to_datetime(df['month'], format='%B').dt.month.astype(str).str.zfill(2))
100 loops, best of 3: 13.5 ms per loop
In [201]: %timeit (df['month'].map({'January':'01','February':'02','December':'12'}))
1000 loops, best of 3: 462 µs per loop
You can use a map:
month2int = {"January":1, "February":2, ...}
combined["month_numeric"] = combined["month"].map(month2int)

Categories