Date Detection program gone wrong - python

I am a novice working on a short program with the purpose of detecting dates and printing out whether the given dates are valid or not. Here's how it looks like :
dateRegex = re.compile(r'''(
(0[1-9]|[12]\d|30|31)
[.\\ /]
(0[1-9]|1[0-2])
[.\\ /]
([1-2][0-9]{3})
)''', re.VERBOSE)
def dateValidation(date):
text = str(pyperclip.paste())
mo = date.findall(text)
for groups in mo:
day = groups[1]
month = groups[2]
year = groups[3]
leapyear = ''
if ( month == '04' or month == '06' or month == '09' or month == '11' ) and ( int(day) > 30 ):
print(f'The {groups[0]} string is not a date.')
continue
if int(year) % 4 == 0:
leapyear += year
if int(year) % 100 == 0:
leapyear = ''
if ( int(year) % 100 == 0 ) and ( int(year) % 400 == 0 ):
leapyear += year
if month == '02' and leapyear == year:
if int(day) > 29:
print(f'The {groups[0]} string is not a date.')
continue
elif month == '02' and leapyear != year:
if int(day) > 28:
print(f'The {groups[0]} string is not a date.')
continue
print(f'The {groups[0]} string is a date.')
dateValidation(dateRegex)
I know a lot of the code isn't clean or practical, so I'm open to suggestions about optimizing it, of course ( I'm fairly new to this after all, and apparently doing horribly ), but the question is mainly regarding the output of the program.
I copied 01.02.2016 21.6.2003 26.7.1999 to clipboard and expected to get a result regarding all three dates. Instead, the output was only ''The 01.02.2016 string is a date.'' Did I overlook something ? What could've gone wrong ?
If it isn't obvious from the code, here is a detailed description of what the program is supposed to do :
Write a regular expression that can detect dates in the DD/MM/YYYY format. Assume that the days range from 01 to 31, the months range from 01 to 12, and the years range from 1000 to 2999. Note that if the day or month is a single digit, it’ll have a leading zero.
The regular expression doesn’t have to detect correct days for each month or for leap years; it will accept nonexistent dates like 31/02/2020 or 31/04/2021. Then store these strings into variables named month, day, and year, and write additional code that can detect if it is a valid date. April, June, September, and November have 30 days, February has 28 days, and the rest of the months have 31 days. February has 29 days in leap years. Leap years are every year evenly divisible by 4, except for years evenly divisible by 100, unless the year is also evenly divisible by 400. Note how this calculation makes it impossible to make a reasonably sized regular expression that can detect a valid date.
Thanks in advance.

I think the problem with the regular expression follows from the format of the dates in the text. Since some of the dates are given as 21.6.2003 and not 21.06.2003, your regex misses that.
For the dates you can use the following one:
r'(0*[0-9]|1[0-9]|2[0-9]|3[0-1])\.(0*[0-9]|1[0-2])\.[1-2][0-9]{3})'
Here,
(0*[0-9]|1[0-9]|2[0-9]|3[0-1]) matches the days ranging in 00-31. In the first case, 0* tells regex to match zero or more of the preceding token. So, if the date is given in 06 or 6 format, it can catch both cases
Similar approach also follows in (0*[0-9]|1[0-2]), which finds the month in the range 00-12

Related

Zybooks Leap year Python function

6.23 LAB: Leap year - functions
A common year in the modern Gregorian Calendar consists of 365 days. In reality, Earth takes longer to rotate around the sun. To account for the difference in time, every 4 years, a leap year takes place. A leap year is when a year has 366 days: An extra day, February 29th. The requirements for a given year to be a leap year are:
The year must be divisible by 4
If the year is a century year (1700, 1800, etc.), the year must be evenly divisible by 400
Some example leap years are 1600, 1712, and 2016.
Write a program that takes in a year and determines the number of days in February for that year.
Ex: If the input is:
1712
the output is:
1712 has 29 days in February.
Ex: If the input is:
1913
the output is:
1913 has 28 days in February.
Your program must define and call the following function. The function should return the number of days in February for the input year.
def days_in_feb(user_year)
Hey guys im having trouble with this problem. I am receiving partial credit for this problem, but im struggling with the last part
2: Unit test
0 / 2
days_in_feb(1913)
Your output
days_in_feb(1913) incorrectly returned False
3: Unit test
0 / 3
days_in_feb(1600)
Your output
days_in_feb(1600) incorrectly returned True
4: Unit test
0 / 3
days_in_feb(1900)
Your output
days_in_feb(1900) incorrectly returned False
This is what i currently have done.
def days_in_feb(year):
leap = year % 4 == 0 and (year % 400 == 0 or year % 100 != 0)
return leap
if name == 'main':
year = int(input())
if days_in_feb(year):
print(year,"has 29 days in February.")
else:
print(year,"has 28 days in February.")
Your code is a little mixed up with your question, format issue, I assume that's why you don't get an answer yet. Since I was also going over Zybooks therefore I just went over this question. Maybe I can show you mine.
def days_in_feb(user_year):
if user_year % 4 == 0 and user_year % 100 != 0: #Condition to check regular leap years
return 29
elif user_year % 400 == 0: #Condition to check XX00s
return 29
else: #Condition for non-leap years
return 28
if __name__ == '__main__':
year = int(input())
day = days_in_feb(int(year))
print(f'{year} has {day} days in February.')

Error: not all arguments converted during string formatting for dd/mm/yyy

beginner python user here.
I need to validate a date string without using the datetime() module.
(hopefully, you can see) the year needs to be greater than 2021, and the date needs to be a valid date including leap years.
So far I have this:
while True:
Date = input('enter date of appointment in dd/mm/yyyy format. ')
day,month,year = Date.split('/')
if month=={1,3,5,7,8,10,12}:
max_days=31
elif month=={4,6,9,11}:
max_days=30
elif year%4==0 and year%100!=0 or year%400==0:
max_days=29
else:
max_days=28
if month<1 or month>12:
print('invalid, enter a number between 1 - 12')
elif day<1 or day>max_days:
print('invalid, check day')
elif year<2022:
print('invalid, enter a year greater than 2021')
else:
break
But I'm getting the error: "not all arguments converted during string formatting" on line 10 which is "elif year%4==0 and year%100!=0 or year%400==0:"
I'm confused as to how to fix it, am I missing another formula?
The day, month and year variables are strings. This means that the when %-operator is used, the string will be interpreted as a format string. But as the strings aren't format strings, it will result in an error.
The solution is to convert the day, month and year variables to an integer.
day_string, month_string, year_string = Date.split('/')
day = int(day_string)
month = int(month_string)
year = int(year_string)
Also in the if statements where you check the maximal day count based on the month, you use if month == {1,3,5,7,8,10,12}: this won't check if the month variable is 1, 3, 5, 7, 8, 10 or 12. To fix this other issue use if month in [1, 3, 5, 7, 8, 10, 12].
Your variables day, month and year resulting from the Date.split('/')~ are strings not int`
Try the following:
while True:
Date = input('enter date of appointment in dd/mm/yyyy format. ')
day,month,year = Date.split('/')
if int(month)=={1,3,5,7,8,10,12}:
max_days=31
elif int(month)=={4,6,9,11}:
max_days=30
elif int(year)%4==0 and int(year)%100!=0 or int(year)%400==0:
max_days=29
else:
max_days=28
if int(month)<1 or int(month)>12:
print('invalid, enter a number between 1 - 12')
elif int(day)<1 or int(day)>max_days:
print('invalid, check day')
elif int(year)<2022:
print('invalid, enter a year greater than 2021')
else:
break

While loop with datetime functions will not work [closed]

Closed. This question is not reproducible or was caused by typos. It is not currently accepting answers.
This question was caused by a typo or a problem that can no longer be reproduced. While similar questions may be on-topic here, this one was resolved in a way less likely to help future readers.
Closed 2 years ago.
Improve this question
For some reason, this while loop will not execute it seems. Can anyone help me possibly?
EDIT: the loop now works but now the alteration in the loop is simply returning an infinite repeating string of July 15, 0559
As for the purpose of this program, it is meant to calculate certain dates of the st. Habakkuk feast day, which is based on an interval of 256 days. It is meant to print the 0th, 10th, first 20th century fest day, and the upcoming feast day along with its ordinal value.
this is an incomplete code as of right now.
from datetime import date, datetime, timedelta
origD = date(559, 7, 14)
print(f"0th Feast day: {origD.strftime('%B'), origD.strftime('%d'), origD.strftime('%Y')}")
day = int(origD.day)
month = int(origD.month)
year = int(origD.year)
dNow = date.today()
yearNow = int(dNow.year)
monthNow = int(dNow.month)
dayNow = int(dNow.day)
daysToFeast = int(0)
whichFeast = int(0)
while not (day == dayNow and month == monthNow and year == yearNow):
nextDay = timedelta(1)
newDate = origD + nextDay
daysToFeast += 1
day = int(newDate.day)
month = int(newDate.month)
year = int(newDate.year)
if daysToFeast == 256:
whichFeast += 1
daysToFeast = 0
if whichFeast == 10:
print(f"10th Feast day: {newDate.strftime('%B'), newDate.strftime('%d'), newDate.strftime('%Y')}")
if year == 1900:
print(f"First 20th Century Feast day: {newDate.strftime('%B'), newDate.strftime('%d'), newDate.strftime('%Y')}")
'''
Boolean operations like not, and and or have precedence rules which govern which operations in an expression are applied first and to which arguments.
For instance, not has higher precedence ('binds' more tightly) than and. So your while condition in the above is actually equivalent to:
(not day == dayNow) and (month == monthNow) and (year == yearNow)
which will be False rather earlier than you intend...
Instead, you can group the expressions to make explicit your intent and to override the precedence rules, e.g.
not (day == dayNow and month == monthNow and year == yearNow)
Doing so allows the while loop body to execute, but reveals some other problems. The solutions may become obvious to you once you encounter them. Nevertheless, I would say your code could be significantly shorter and simpler.
For example, why bother maintaining separate variables for days, months, years etc. when the datetime module can step through days (somedate += timedelta(days=1)) and maintain that information for you? This would certainly make the while condition more readable (not date1 == date2), and might help you (and StackOverflow contributors) identify where the problems are coming from. Here is my attempt and making your code more concise, and which prints the 10th 'feast day':
from datetime import date, timedelta
then = date(559, 7, 14)
print(f"0th Feast day: {then.strftime('(%B, %d, %Y)')}")
now = date.today()
print(f"Today: {now.strftime('(%B, %d, %Y)')}")
whichFeast = 0
while then < now:
then += timedelta(days=256)
whichFeast += 1
if whichFeast == 10:
print(f"10th Feast day: {then.strftime('(%B, %d, %Y)')}")
Disregarding the rest of the code, the loop does not start because of
while not day == dayNow and month == monthNow and year == yearNow:
( that is the same of
while not (day == dayNow) and (month == monthNow) and (year == yearNow):
that always returns False )
try
while not (day == dayNow and month == monthNow and year == yearNow):

Python Date game, Future/Past determination

Issue:
My program keeps telling me, no matter what, that my date is invalid.
Assignment:
The user will input a year, a month number (1-12), and a day number in that order. The program will
determine if the date is in the future, or in the past. (If the date entered is today’s date, assume the date
is in the past). A future date is a date that has not happened yet. If today is July 31st, August 1 of the
same year is not in the past, just because the day (1) comes before today’s day (31). For the input, if the user enters an invalid month, display an appropriate error message (like “Invalid
Month”) and end the program. If the user enters an invalid day, display an appropriate error message
(like “Invalid Day”) and end the program. Assume 28 days in February. In other words, if the month is
February and the day entered is 29, display the error message and end the program.
Remember:
Thirty days has September,
April, June, and November
All the rest have 31
Except February, which has 28….
Define a function called inTheFuture() that accepts a given year number, a month number, and a
day number as 3 separate arguments. The function should return a Boolean value (True or False) to
indicate whether the date (year, month, and day) parameters are in the future or not. A True return
occurs if the date is in the future; False if the date is in the past. It should not draw any images or text to
the screen. It also should not ask the user for input. It just determines if a given date is in the future or
not.
Find an image to represent the future, and an image to represent the past. Examples could include
something like “The Jetson’s” for the future, and an old wagon for the past.If the date is in the future, display your future image in the middle of a canvas. If the date is in the past,
display your past image in the middle of the canvas. At the top of the canvas, display “In the future” or
“In the past”, whichever matches the image.
To find the current date, you may add this import and function to your code:
import datetime
def getTodaysDate():
return datetime.datetime.today()
If you call this function somewhere in your code:
today = getTodaysDate()
Then you can use the year, month, and day member variables to obtain the current year, month, and
day. For example:
print(today.month)
would output the current month.
Here is my program that I thought was finished. What am I missing?
This works for a date input like "24.12.2016". Change it to your needs in the line of strptime().
import datetime
from time import strptime
def date_in_the_future(date):
datetime_string = strptime(date, "%d.%m.%Y")
d = datetime.datetime(datetime_string[0],datetime_string[1],datetime_string[2])
now = datetime.datetime.now()
delta = d - now
diff = delta.days + 1
if diff > 0:
return True
else:
return False
You should learn how to use if,else, and elif. Check the code below:
import datetime
def getTodaysDate():
return datetime.datetime.today();
today = getTodaysDate();
print(today)
#def inTheFuture():
year= input ("Enter Year: ");
month= int(input ("Enter Month: "));
day= int(input ("Enter Day: "));
print"Correct, Your Day is:",day,"/",month,"/",year
if (month > 12):
print("How many months in a year? Not as many as you think I suppose..")
raise SystemExit
elif month in [1,3,5,7,8,10,12]:
if day > 31:
print("What is a month where you are from?")
raise SystemExit
else:
print"Correct, Your Day is:",day,"/",month,"/",year
elif (month == 2):
if (day > 28):
print("February only has so many days!")
raise SystemExit
else:
print"Correct, Your Day is:",day,"/",month,"/",year
elif (month in [4,6,9,11]):
if (day > 30):
print("That day is not possible!")
else:
print"Correct, Your Day is:",day,"/",month,"/",year

Parsing date string in Python

How can I rewrite following clause:
if u'января' in date_category['title']:
month = 1
elif u'февраля' in date_category['title']:
month = 2
elif u'марта' in date_category['title']:
month = 3
elif u'апреля' in date_category['title']:
month = 4
elif u'мая' in date_category['title']:
month = 5
elif u'июня' in date_category['title']:
month = 6
elif u'июля' in date_category['title']:
month = 7
elif u'августа' in date_category['title']:
month = 8
elif u'сентября' in date_category['title']:
month = 9
elif u'октября' in date_category['title']:
month = 10
elif u'ноября' in date_category['title']:
month = 11
elif u'декабря' in date_category['title']:
month = 12
It just looks ugly.
To solve this, parse your date information using the python datetime module. It has support for locales, and will sort this out. If genitive forms are really the issue, then just map those forms to the dative, then map back on output.
To answer your actual question -
Consider that you are pairing up data with integers. If you can transform your data into the format (month, integer), you can drive your code with data.
for (n, month) in enumerate(u'января, feb, mar, apri, may, jun, jul, aug, sep, oct, nov, декабря'.split(', '), 1):# the parameter 1 specifies to start counting from 1. h/t #san4ez
if month in date_category['title']: return n
Get system support for Russian internationalization: OS locale support for use in Python
Use the locale module to set the locale: How to get unicode month name in Python?
Use strptime: Handling international dates in python
Demonstration: Locale troubles
Alternatively, just do:
months = ['Jan', 'Feb', 'Mar', ...]
monthToNumber = dict((name,i+1) for i,name in enumerate(months))
monthToNumber[date_category['title']]
months = (u'января', u'февраля', u'марта', u'апреля', u'мая', u'июня', u'июля', u'августа', u'сентября', u'октября', u'ноября', u'декабря')
month = next(i for i,name in enumerate(months,1) if name in date_category['title'])
You may also use the index function in list to get a mapping of months to months number
months = (u'января', u'февраля', u'марта', u'апреля', u'мая', u'июня', u'июля', u'августа', u'сентября', u'октября', u'ноября', u'декабря')
month = months.index(date_category['title'])+1
Create a dict of the months, with corresponding indices:
months = [u'января', u'февраля', u'марта', u'апреля', u'мая', u'июня', u'июля', u'августа', u'сентября', u'октября', u'ноября', u'декабря']
Then you can simply do:
month = max(enumerate((date_category['title'].find(month) for month in months), start = 1), key = lambda x: x[1])[0]
Simply create a hash array which maps your string to corresponding month number, then you can simply iterate through it, check where the key is in date_category['title'], and in all cases, set month to the corresponding value. Good luck.
Here's something a bit more perverse, because I enjoy proving the futility of saying "there should be only one way to do it":
pattern = re.compile(u'(января)|(февраля)|(марта)|(апреля)|(мая)|(июня)|(июля)|(августа)|(сентября)|(октября)|(ноября)|(декабря)')
month = map(bool, x.search(date_category['title']).groups()).index(True) + 1

Categories

Resources