Seemingly strange behavior with python counter program - python

A portion of a recent assignment was to design a program that counts days between dates. I have yet to finish, and I know this could be improved drastically. However, my question is: when I run this program with date2 (below), an error occurs, but this runs as planned with date1 (again, below). I find this behavior strange. These dates are only one day apart and yet one fails and one doesn't. I've tried this with multiple dates, but each fails after 994 days regardless of month, year, day, whatever. Why?
clarification: I define "fail" as
File "first.py", line 35, in counter
return counter(date_array, x+1)
.
def date_test(date_array):
first = (date_array[0], date_array[1], date_array[2])
second = (date_array[3], date_array[4], date_array[5])
if first > second:
return False
elif first != second:
return True
elif first == second:
return False
else:
return "Error: This shouldn't happen."
def counter(date_array, x = 0):
months = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
while(date_test(date_array)):
if(date_array[2] == 31 and date_array[1] == 12):
date_array[0] += 1; date_array[1], date_array[2] = 1, 1
return counter(date_array, x+1)
else:
if date_array[2] < months[date_array[1]-1]:
date_array[2] += 1
return counter(date_array, x+1)
else:
date_array[1] += 1; date_array[2] = 1;
return counter(date_array, x+1);
return x
def tuple_test(date):
date_array = []
for x in date:
date_array.append(x)
if not date_test(date_array):
return "The first date is before the second. Swap them."
return counter(date_array)
date1 = (1900,1,1,1902,9,22)
date2 = (1900,1,1,1902,9,23)
print tuple_test(date1)
print tuple_test(date2)

The reason for the error is that you've exceeded your maximum recursion depth.
To "hack" (and verify) this problem you could simply add
import sys
sys.setrecursionlimit(10000)
to the top of your code

you should use the tools python provides
>>> import datetime
>>> date1 = (1900,1,1,1902,9,22) #your weird list with 2 dates
>>> dt1 = datetime.date(*date1[:3]) #create a date object == datetime.date(1900,1,1)
>>> dt2 = datetime.date(*date1[3:]) #create a date object == datetime.date(1902,9,22)
>>> if dt1 < dt2: dt1,dt2 = dt2,dt1 #if dt1 is smaller than dt2, swap them
...
>>> print (dt1 - dt2).days #subtract them and print their days
994
>>>

Related

Need help in finding the day of given (year,month,date) in python

def isYearLeap(year): # Leap year formula
if year % 4 == 0 and year % 100 != 0 :
return True
elif year % 400 == 0 :
return True
else :
return False
testData = [1900, 2000, 2016, 1987] # Test Data as reference
testResults = [False, True, True, False]
for i in range(len(testData)):
yr = testData[i]
print(yr,"->",end="")
result = isYearLeap(yr)
if result == testResults[i]:
print("OK")
else:
print("Failed")
def daysInMonth(year, month): # Finding out days in months in common & leap year
days = 0
mo31 = [1,3,7,5,8,10,12]
if year % 4 == 0 :
days = 1
if year % 100 == 0 :
days = 0
if year % 400 == 0 :
days = 1
if month == 2 :
return 28 + days
if month in mo31 :
return 31
return 30
testYears = [1900, 2000, 2016, 1987] # Test Data as reference
testMonths = [2, 2, 1, 11]
testResults = [28, 29, 31, 30]
for i in range(len(testYears)):
yr = testYears[i]
mo = testMonths[i]
print(yr, mo, "->", end="")
result = daysInMonth(yr, mo)
if result == testResults[i]:
print("OK")
else:
print("Failed")
def dayOfYear(year, month, day):
doy = ["Sat","Sun","Mon","Tue","Wed","Thu","Fri"] # Days of week
monthvalue = [1,4,4,0,2,5,0,3,6,1,4,6] # Months value zellers rule
century = [1700,1800,1900,2000] # Zellers rule
value = [4,2,0,6] # Zellers rule
rem = 0 # Remainder Variable
r = [] # Empty List to compare remainder and to a doy
y = str(year) # Converting year into string
y = int(y[2:4]) # Taking last two digits of string & if used return the function ends
y = int(year) # here returning last two digits
m = int(month)
d = int(day)
mo = [] # Empty list for comparing month with monthly values
dd = 0
if dd == 0 :
for i in range(len(monthvalue)) :
mo.append(i) # Creating mo list
if m in mo:
mo[i] == monthvalue[i]
dd = y // 4 + d + m
if m >= 2 :
dd -= 1
dd += y
for i in range(len(value)) :
if y in century :
y = century[i] == value[i]
dd += y
rem = dd % 7
for i in range(len(doy)) :
r.append(i) # Creating r list
if rem in r :
rem = r[i] == doy[i]
print(rem)
print(dayOfYear(2000, 12, 31)) # Giving output False "\n None
Your code contains a lot of illogical statements and redundancies, that make the code hard to read/understand.
I'd recommend first looking into a few style guides or more basic python tutorials.
Some examples:
y = str(year) # Converting year into string
y = int(y[2:4]) # Taking last two digits of string & if used return the function ends
y = int(year) # here returning last two digits
While the first two statements don't have any effect, their comments makes me think you forgot about two lines of code in between.
dd = 0
if dd == 0 :
...
That if check will never evaluate to false, so it's redundant
for i in range(len(monthvalue)) :
mo.append(i) # Creating mo list
if m in mo:
mo[i] == monthvalue[i]
The mo variable/list is never used again
Please check your program flow and report back
I recognize this as a lab in the netacad cisco python course.
You were tasked with creating an is_year_leap() function in LAB 4.3.1.6, a days_in_month() function in LAB 4.3.1.7, and a day_of_year() function in LAB 4.3.1.8. The functions have one, two, three parameters respectively. Please see below code. Note that I excluded a code to return None if any of the arguments are invalid. I would like you to add that on your own as learning.
# from LAB 4.3.1.6
def is_year_leap(year):
if year % 4 == 0: # leap year occur every 4 years & is divisible by 4
return True
else:
return False
# from LAB 4.3.1.7
def days_in_month(year, month):
# Create list with month days for each month as advised in the LAB
month_days = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
if is_year_leap(year):
month_days[1] = 29 # 29 days for February on a leap year.
return month_days[month - 1] # month 1 corresponds with index 0 & so on.
# for LAB 4.3.1.8
def day_of_year(year, month, day):
total = 0 # initializing the total variable to add results
# create loop to add only days in the months before the month in the input/test data
for i in range(1, month):
result = days_in_month(year, i)
total += result
day_num = total + day # add the value of the day argument to get day of the year
return day_num
# test data
print(day_of_year(2000, 12, 31))
print(day_of_year(1999, 12, 31))
print(day_of_year(2021, 7, 29))
A point to note is the occurrence of days above the number of days of months.
def is_year_leap(year):
return year % 4 == 0 and not year % 100 == 0 or year % 400 == 0
def days_in_month(year, month):
days = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
if is_year_leap(year):
days[1] = 29
return days[month - 1]
def day_of_year(year, month, day):
if day <= days_in_month(year, month):
count = 0
for yr in range(1, month):
count += days_in_month(year, yr)
return count + day
The leap year should fulfil all its conditions for getting the day of the year.
if the year is divisible by 400 then is_leap_year,
else if the year is divisible by 100 then not_leap_year
else if the year is divisible by 4 then is_leap_year
else not_leap_year
The number of days should also be checked whether it exceeds the day in the month.
#Check for leap year
def is_year_leap(year):
if year%400==0 or (year%100 != 0 and year%4==0):
return True
else:
return False
#Check for number of days in month
def days_in_month(year, month):
month31=[1,3,5,7,8,10,12]
if month in month31:
return 31
elif(month == 2):
if(is_year_leap(year)):
return 29
else:
return 28
else:
return 30
#Check for corresponding day of the year
def day_of_year(year, month, day):
total = 0
if day <= days_in_month(year, month):
total = day
for i in range(month-1):
total += days_in_month(year, i)
return total
else:
return "Your month doesn't have that many days."
print(day_of_year(2000, 12, 31))
print(day_of_year(2001, 12, 31))
print(day_of_year(2008, 12, 31))
print(day_of_year(2000, 11, 31))

Code to check if current time is before due time

I am trying to see if the current hour, time and section is before the due hour, due minute and due section then it should print true otherwise false. My code is not working and ive been working on this for 2 hours
current_hour = 12
current_minute = 37
current_section = "PM"
due_hour = 9
due_minute = 0
due_section = "AM"
if (((current_hour < 9) and (current_hour != 12)) and (current_minute != 0) and current_section):
print("True")
else:
print("False")
Your current code is failing (presumably) because you're using 'and current_section' which will pass True for any value of current_selection.
Using the datetime library makes this quite simple:
from datetime import datetime
due_time = datetime.strptime('9:00AM','%I:%M%p')
curr_time = datetime.strptime('12:37PM','%I:%M%p')
diff_seconds = (curr_time - due_time).total_seconds()
if diff_seconds > 0:
print('False')
else:
print('True')
You can also add dates to make it more robust (see https://stackoverflow.com/a/466376/10475762 for more information on how to use strptime).

Writing and using your own functions - basics

Your task is to write and test a function which takes two arguments (a year and a month) and returns the number of days for the given month/year pair (yes, we know that only February is sensitive to the year value, but we want our function to be universal). Now, convince the function to return None if its arguments don't make sense.
Use a list filled with the months' lengths. You can create it inside the function - this trick will significantly shorten the code.
I have got the code down but not the 'none' part. Can someone help me with this?
def IsYearLeap(year):
if (year%4==0):
return True
if (year%4!=0):
return False
def DaysInMonth(year,month):
if month in {1, 3, 5, 7, 8, 10, 12}:
return 31
elif month==2:
if IsYearLeap(year):
return 29
else:
return 28
elif month in {4,6,8,9,11}:
return 30
else:
return none
testyears = [1900, 2000, 2016, 1987,2019]
testmonths = [ 2, 2, 1, 11,4]
testresults = [28, 29, 31, 30,33]
for i in range(len(testyears)):
yr = testyears[i]
mo = testmonths[i]
print(yr,mo,"->",end="")
result = DaysInMonth(yr,mo)
if result == testresults[i]:
print("OK")
else:
print("Failed")
It seems that you have rather made a simple mistake. If you are not used the case-sensitive programming languages or have no experience in programming languages, this is understandable.
The keyword None is being misspelled as the undefined word none.
I think your testresults is wrong. February of 1900 should be 29 days also April of 2019 30 days. Also its None instead none. Another things also its better to using list on months list so you could using [1, 3, 5, 7, ...] instead {1, 3, 5, 7, ...}.
Also from your test cases you won't got None, in case you want check this case you could check with month = 13, and you will cover this case
As a further comment to the other good answers to this question, the correct rule for leap years should be something like:
def is_leap_year(year):
""" is it a leap year?
>>> is_leap_year(1984)
True
>>> is_leap_year(1985)
False
>>> is_leap_year(1900)
False
>>> is_leap_year(2000)
True
"""
return (year % 4 == 0 and
(year % 100 != 0 or year % 400 == 0))
Similarly, the test cases need to be clear that 1900 was not a leap year, 2000 was. I recommend writing a separate set of test cases for is_leap_year. Ultimately, in production code, you will be better off to use one of the many time/date libraries. The comments that I've provided make use of doctest to provide this unit test quickly.
A function which does not explicitly return anything implicitly returns None.
In addition to the spelling error (none vs None) you are using this by accident here:
def IsYearLeap(year):
if (year%4==0):
return True
if (year%4!=0):
return False
Can you see what will happen if neither of the conditions is true? It won't return either False or True, which presumably the caller expects. (Though if you check whether None == True you will get False, and not None is True, so you won't get a syntax error, just a result which might be different from what you expect - the worst kind of bug!)
def IsYearLeap(year):
return year % 4 == 0 & (year % 400 == 0 | year % 100 != 0)
def DaysInMonth(year,month):
if month in [1, 3, 5, 7, 8, 10, 12]:
return 31
elif month==2:
if IsYearLeap(year):
return 29
else:
return 28
elif month in [4,6,8,9,11]:
return 30
else:
return None
#
testYears = [1900, 2000, 2016, 1987]
testMonths = [2, 2, 1, 11]
testResults = [28, 29, 31, 30]
for i in range(len(testYears)):
yr = testYears[i]
mo = testMonths[i]
print(yr, mo, "->", end="")
result = DaysInMonth(yr, mo)
if result == testResults[i]:
print("OK")
else:
print("Failed")
def is_year_leap(year):
return year % 4 == 0 and year % 100 != 0 or year % 400 == 0
def days_in_month(year, month):
days = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
if type(year) != int or year < 1582 or\
type(month) != int or month < 1 or month > 12:
return None
elif is_year_leap(year):
del days[1]
days.insert(1, 29)
return days[month - 1]
test_years = [1900, 2000, 2016, 1987]
test_months = [2, 2, 1, 11]
test_results = [28, 29, 31, 30]
for i in range(len(test_years)):
yr = test_years[i]
mo = test_months[i]
print(yr, mo, "->", end="")
result = days_in_month(yr, mo)
if result == test_results[i]:
print("OK")
else:
print("Failed")
A few minor remarks:
You should remove the duplicate 8th month (August is listed for 30 and 31 days),
Better replace brackets {} with the list [],
Replace none with None (Python is case-sensitive, None is the keyword),
Add one more condition for a leap year:
(year % 400 == 0) and (year % 100 == 0) -> return True
(year % 4 == 0) and (year % 100 != 0) -> return True

Count number of sundays in current month

How can I get the numberof Sundays of the current month in Python?
Anyone got any idea about this?
This gives you the number of sundays in a current month as you wanted:
import calendar
from datetime import datetime
In [367]: len([1 for i in calendar.monthcalendar(datetime.now().year,
datetime.now().month) if i[6] != 0])
Out[367]: 4
I happened to need a solution for this, but was unsatisfactory with the solutions here, so I came up with my own:
import calendar
year = 2016
month = 3
day_to_count = calendar.SUNDAY
matrix = calendar.monthcalendar(year,month)
num_days = sum(1 for x in matrix if x[day_to_count] != 0)
I'd do it like this:
import datetime
today = datetime.date.today()
day = datetime.date(today.year, today.month, 1)
single_day = datetime.timedelta(days=1)
sundays = 0
while day.month == today.month:
if day.weekday() == 6:
sundays += 1
day += single_day
print 'Sundays:', sundays
My take: (saves having to worry about being in the right month etc...)
from calendar import weekday, monthrange, SUNDAY
y, m = 2012, 10
days = [weekday(y, m, d+1) for d in range(*monthrange(y, m))]
print days.count(SUNDAY)
Or, as #mgilson has pointed out, you can do away with the list-comp, and wrap it all up as a generator:
sum(1 for d in range(*monthrange(y,m)) if weekday(y,m,d+1)==SUNDAY)
And I suppose, you could throw in a:
from collections import Counter
days = Counter(weekday(y, m, d + 1) for d in range(*monthrange(y, m)))
print days[SUNDAY]
Another example using calendar and datetime:
import datetime
import calendar
today = datetime.date.today()
m = today.month
y = today.year
sum(1 for week in calendar.monthcalendar(y,m) if week[-1])
Perhaps a slightly faster way to do it would be:
first_day,month_len = monthrange(y,m)
date_of_first_sun = 1+6-first_day
print sum(1 for x in range(date_of_first_sun,month_len+1,7))
You can do this using ISO week numbers:
from datetime import date
bom = date.today().replace(day=1) # first day of current month
eom = (date(bom.year, 12, 31) if bom.month == 12 else
(bom.replace(month=bom.month + 1) - 1)) # last day of current month
_, b_week, _ = bom.isocalendar()
_, e_week, e_weekday = eom.isocalendar()
num_sundays = (e_week - b_week) + (1 if e_weekday == 7 else 0)
In general for a particular day of the week (1 = Monday, 7 = Sunday) the calculation is:
num_days = ((e_week - b_week) +
(-1 if b_weekday > day else 0) +
( 1 if e_weekday >= day else 0))
import calendar
MONTH = 10
sundays = 0
cal = calendar.Calendar()
for day in cal.itermonthdates(2012, MONTH):
if day.weekday() == 6 and day.month == MONTH:
sundays += 1
PAY ATTENTION:
Here are the Calendar.itermonthdates's docs:
Return an iterator for one month. The iterator will yield datetime.date
values and will always iterate through complete weeks, so it will yield
dates outside the specified month.
That's why day.month == MONTH is needed
If you want the weekdays to be in range 0-6, use day.weekday(),
if you want them to be in range 1-7, use day.isoweekday()
My solution.
The following was inspired by #Lingson's answer, but I think it does lesser loops.
import calendar
def get_number_of_weekdays(year: int, month: int) -> list:
main_calendar = calendar.monthcalendar(year, month)
number_of_weeks = len(main_calendar)
number_of_weekdays = []
for i in range(7):
number_of_weekday = number_of_weeks
if main_calendar[0][i] == 0:
number_of_weekday -= 1
if main_calendar[-1][i] == 0:
number_of_weekday -= 1
number_of_weekdays.append(number_of_weekday)
return sum(number_of_weekdays) # In my application I needed the number of each weekday, so you could return just the list to do that.

Printing during different times of week

Welp, I'm a noob when it comes to Python. No doubt about it. Have done some VBS and VB so I have a bit of understanding.
What I am tasked to do using Python seems easy: run an action only during these times:
Mon: between 1:30 am and 7:30 am
Tues – Fri: between 3:00 am 7:30 am
Sat: between 1:00 am and 9:00 am and 5:00 pm to Midnight
Sun: Midnight to 8:30 am
Trouble is, all I've been able to come up with is this (and I'm not even sure this is working properly):
import time
def IsOffHour(time):
if (time.tm_wday > 4):
return True
elif (time.tm_hour >= 17):
return True
elif (time.tm_hour < 8):
return True
else:
return False
now = time.localtime()
if IsOffHour(now):
print 'hello cruel world !'
I'm not sure how to handle the times that start at :30. It's been a bit hard to test, maybe I can change the system date and dime to test it out.
It seems like I'm close, open to ideas.
Thanks!
Instead of using the time module you should try the datetime module. It's much easier for tasks like these.
If you use a fictional date (or replace the date in your checks) than you can do it like this:
>>> x = datetime.datetime(1, 1, 1, 13, 37, 40)
>>> a = datetime.datetime(1, 1, 1, 1, 30, 0)
>>> b = datetime.datetime(1, 1, 1, 7, 30, 0)
>>> a < x < b
False
>>> x = datetime.datetime(1, 1, 1, 5, 0, 0)
>>> a < x < b
True
My ideas:
do check for each day separately (if time_wday == ... or if time_wday in [...])
for checking hours convert them to 24h based string (there is strftime()) and then compare as strings, so instead of time.tm_hour >= .. this will look as hrstr > '13:30' and hrstr < '19:30'
this gives code like:
def IsOffHour(dt):
hrstr = '%02d:%02d' % (dt.tm_hour, dt.tm_min)
if dt.tm_wday == 0:
return '01:30' <= hrstr <= '07:30'
if dt.tm_wday in [1, 2, 3, 4]:
return '03:00' <= hrstr <= '07:30'
if dt.tm_wday == 5:
return '01:00' <= hrstr <= '09:00' or hrstr >= '17:00'
if dt.tm_wday == 6:
return hrstr <= '08:30'
return False
What you should be doing is comparing time objects to time objects rather than extracting the hours and minutes and doing this by hand.
So define the acceptable time windows in your script using time objects and then just see if the current time falls in any of the those windows.
from datetime import datetime,time
# Set our allowed time windows in a dictionay indexed by day, with 0 =
# Monday, 1 = Tuesday etc. Each value is list of tuples, the tuple
# containing the start and end time of each window in that day
off_windows = {
0: [(time(1,30),time(7,30))],
1: [(time(3,0),time(7,30))],
2: [(time(3,0),time(7,30))],
3: [(time(3,0),time(7,30))],
4: [(time(3,0),time(7,30))],
5: [(time(1,0),time(9,0)),(time(16,0),time.max)], #time.max is just before midnight
6: [(time(0,0),time(8,30))]
}
def is_off_hours():
# Get current datetime
current = datetime.now()
# get day of week and time
current_time = current.time()
current_day = current.weekday()
# see if the time falls in any of the windows for today
return any(start <= current_time <= end for (start,end) in off_windows[current_day])
if is_off_hours():
print 'Hello cruel world!'
Above we use the any function which returns True if any value of an iterable is True. So he code loops through the off windows which we have defined for a day, returning true if the current time falls within any of them.
A nice this about python is we can say:
start <= current_time <= end
instead of
start <= current_time and current_time <= end

Categories