# Inifinite loop for outdated problem

I am working on the "outdated" problem.

I need to reformat the output given by the user in order to adehere to the ISO format.

My code is as follows:

``````months = ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"]

months_and_number = {"January":"01", "February":"02", "March":"03", "April":"04", "May":"05", "June":"06", "July":"07", "August":"08", "September":"09", "October":"10", "November":"11", "December":"12"}

while True:
try:
x = input("Date: ")
test_coma = x.index("," or "/")
except ValueError:
x = input("Date: ")
else:
if "," in x:
split_coma = x.split(",")
if len(split_coma) <2 and len(split_coma) > 2:
x = input("Date: ")
else:
if len(split_coma[1]) < 4 or len(split_coma[1]) > 4:
x = input("Date: ")
else:
year = split_coma[1]
if months not in split_coma[0]:
x = input("Date: ")
else:
split_space = split_coma[0].split(" ")
if split_space[0] in months_and_number:
months = months_and_number[split_space[0]]
else:
x = input("Date: ")
if len(split_space[1]) < 2:
day = "0" + split_space[1]
else:
day = split_space[1]

iso = year + "-" + months + "-" + day
print(iso)

else:
y = x.split("/")
if len(y) < 3 and len(y) > 3:
x = input("Date: ")
else:
if len(y[0]) < 2:
a = "0" + y[0]
else:
a = y[0]
if len(y[1]) < 2:
b = "0" + y[1]
else:
b = y[1]
c = y[2]
new_date = y[2] + "-" + y[0] + "-" + y[1]
print(new_date)
``````

I know that it is far from perfect, with a lot of conditions within conditions, but still it should work. But it does not.

I am always prompted to give a date after another, indefinitely. Why?

=======================

Here is the updated code, based on your help:

``````  list_months = [    "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"]

list_day_months = ["0","1","2","3","4","5","6","7","8","9","10","11","12","13","14","15","16","17","18","19","20","21","22","23","24","25","26","27","28","29","30"]

dic_months_numb = {"January": "1", "February":"2", "March":"3", "April":"4", "May":"5", "June":"6", "July":"7", "August":"8", "September":"9", "October":"10", "November":"11", "December":"12"}

** Process exited - Return Code: 0 **
Press Enter to exit terminal]

date = input("Date ")

def isValid(value):
if "," or "/" not in value:
return False
else:
if "," in value:
return isValidComma(value)
else:
return isValidSlash(value)

def isValidComma(value):
"""Determines if value is a valid date in comma format"""
# reminder comma format is "month_as_word (D)D, YYYY"
# perform needed checks here
check_coma = value.split()
month = check_coma[0]
day_comma = check_coma[1]
year = check_coma[2]
day = day_comma.replace(",", "")
if (month not in list_months) or (len(day) > 2 and day not in list_day_months) or (len(year) > 4 and year.isnumeric() = False ):
return False

def isValidSlash(value):
"""Determines if value is a valid date in Slash format"""
# reminder slash format is "(M)M/(D)D/YYYY"
# perform needed checks here
check_slash = value.split("/")
month = check_slash[0]
day = check_slash[1]
year = check_slash[2]
if (not 1 < month < 12) or (not 1 < day < 31) or (not 1 000 < year < 10 000)
return False

def convertFromComma(value):
"""returns proper year, month and day from the comma based value"""
# reminder comma format is "month_as_word (D)D, YYYY"
for month in dic_months_numb:
month_numb = dic_months_numb[month]

return year, month, day

#**I start to have significant issue here. How is the function going to "know" what to take? What will "value" refer to?**

def convertFromSlash(value):
"""returns proper year, month and day from slash based value"""
#do stuff
return year, month, day

# Main Code

valid = False
while not valid: #3
try:
x = input("Date: ") #1
valid = isValid(x): #2
except ValueError:
valid = False
#end of try block

#while block completed

#now determine which format it is and convert it
#4
if ',' in x:
year, month, day = convertFromComma(x)
else:
year, month, day = convertFromSlash(x)

print(f"{year:04}-{month:02}-{day:02}")
``````

====================

Here is a further update:

``````def isValidSlash(value):
"""Determines if value is a valid date in Slash format"""

month, day, year = value.split("/")
if (1 < int(month) or int(month) > 12) or (1 < int(day) or int(day) > 31) or (1000 < int(year) or int(year) > 10000):

#I had an error here when testing, telling me that the operator "<" cannot be used with "int" and "str", which makes sense. I thus converted day, month and year as string, but this is still not correct. I do not get an error, but when inputting a date I get re prompted again and again.

return False
else:
return True

def convertFromComma(value):
"""returns proper year, month and day from the comma based value"""
# reminder comma format is "month_as_word (D)D, YYYY"

month, day, year = value.split()

day = day.rstrip(',')

month = months[month]
#I added the look up in the dictionary, because the month is given with letter and we would like to look up the number of the month.

return year, month, day
``````

I also changed the f string in the end, to have a zero "leading" (in front? Padding) rather than added at the back:

``````print(f"{year:04}-{month:>02}-{day:>02}")
``````
• don't use try/except/else.. its a very very very bad practice. and not needed here. Commented Mar 13 at 16:26
• add print outs at your decision points and see why you are always prompting again. Commented Mar 13 at 16:27
• you never use test_coma? Commented Mar 13 at 16:28
• I didnt say dont use exceptions i said dont use try/except/else just use try/except. i would only use the else if i needed to also use finally as in try/except/else/finally. The else is generally unnecessary Commented Mar 13 at 17:09
• `test_coma` is your own variable you create but never use Commented Mar 13 at 17:10

Adding another answer based on your new code. I'm giong to make some changes in that code and point out my changes with comments.

NOTE THIS ANSWER ACTUALLY HAS AN ERROR IN IT WHICH I HAVE DELIBERATELY LEFT IN IT SO THAT IT DOESNT VIOLATE HONOR CODE BY PROVIDING A COMPLETE CORRECT SOLUTION ALTHOUGH ITS STILL KINDA QUESTIONABLE. MODS IF THIS CODE NEEDS TO BE DELETED BY ALL MEANS DELETE IT, THIS WAS THE BEST WAY I COULD THINK OF TO HELP OP AFTER ALL THE BACK AND FORTH

``````
# removed list_months you don't need it!

# renamed because the name is ugly
# also removing 0 because 0 is not a valid day of a month, added 31 cuz its valid
days = ["1","2","3","4","5","6","7","8","9","10","11","12","13","14","15","16","17","18","19","20","21","22","23","24","25","26","27","28","29","30","31"]

# reformatting this to be legible
# renaming to be intelligent
months = {
"January" : "1",
"February" : "2",
"March" : "3",
"April" : "4",
"May" : "5",
"June" : "6",
"July" : "7",
"August" : "8",
"September" : "9",
"October" : "10",
"November" : "11",
"December" : "12"
}

#removed don't do this yet! NO WE ARE DEFINING FUNCTIONS
#date = input("Date ")

def isValid(value):
# rewrite cuz this is wrong and silly
if "," in value:
return isValidComma(value)
elif "/" in value:
return isValidSlash(value)
else
return False

def isValidComma(value):
"""Determines if value is a valid date in comma format"""
# reminder comma format is "month_as_word (D)D, YYYY"
# perform needed checks here

# do this properly, split on spaces to 3 values
month, day, year = value.split()
# remove the trailing comma from the day
day = day.rstrip(',')  # this will strip ',' from the end (hence the r)

# notice the rewrite and regrouping and changing
if (month not in months) or (len(day) > 2) or (day not in days) or (len(year) > 4) or not year.isnumeric():
return False
# YOU MISSED THE RETURN TRUE
else
return True

def isValidSlash(value):
"""Determines if value is a valid date in Slash format"""
# reminder slash format is "(M)M/(D)D/YYYY"
# perform needed checks here

# DO THIS IN ONE STEP
month, day, year = value.split("/")

#if (not 1 < month < 12) or (not 1 < day < 31) or (not 1 000 < year < 10 000)
# rewrite your logic becuase its broken and wrong
if 1 < month or month > 12 or 1 < day or day > 31 or 1000 < year or year > 10000:
return False
else:
return True

def convertFromComma(value):
"""returns proper year, month and day from the comma based value"""
# reminder comma format is "month_as_word (D)D, YYYY"

#### COMPLETELY WRONG this doesnt make sense at all
#for month in dic_months_numb:
#month_numb = dic_months_numb[month]
# where did year month and day come from???
#        return year, month, day

#recall this logic from before but now we know its all good we dont have to check it
month, day, year = value.split()
# remove the trailing comma from the day
day = day.rstrip(',')  # this will strip ',' from the end (hence the r)

# return in the order expected!
return year, month day

#**I start to have significant issue here. How is the function going to "know" what to take? What will "value" refer to?**
# THE FUNCTION DOENST KNOW WHAT TO TAKE IT, IT TAKES WHAT WE GIVE IT. WHICH WILL
ONLY EVER BE SLASH FORMATTED DATES!!  JUST LIKE convertFromComma only gets comma-formatted dates

def convertFromSlash(value):
"""returns proper year, month and day from slash based value"""
# you already checked that its validly / formatted so just grab the values and return them properly
month, day, year = value.split("/") # from above!
return year, month, day

# Main Code

valid = False
while not valid: #3
try:
x = input("Date: ")
valid = isValid(x)
except ValueError:
valid = False
#end of try block
#while block completed

#now determine which format it is and convert it

if ',' in x:
year, month, day = convertFromComma(x)
else:
year, month, day = convertFromSlash(x)

print(f"{year:04}-{month:02}-{day:02}")

``````
• Becuase the dictionary you already made of months to month numbers provides that data. the keys to a dictionary are a set. rule 1 of programming DRY (Don't Repeat Yourself) Commented Mar 28 at 21:41
• 1. Yes you define functions before using them Commented Mar 31 at 18:31
• 2. i dont think that line of code as written will work, to be honest im not sure the or is going to group the way you want it.. i know you are trying to say "if neither comma nor slash is in the value" but i dont believe that is what that code translates to. There is a simpler way to code this that is more idiomatic. if one is in it go that route, else if the other is go that route, else return false. Commented Mar 31 at 18:34
• 3. your understanding of converFromComma is kinda true, we are kinda repeating ourselves. but also i realized i made a mistake, i dont handle the case where there arent three values to obtain from the split.we have to deal with that possibility in both of the checks, where as in the converts we can take it for granted. your intuition is right and a further refinement could be combining the two things, so that you return a triple of `None, None, None` if it is invalid and then you dont have to do things twice. I just wanted to get you structurally setup Commented Mar 31 at 18:40
• 4. about your understanding with the update, all the code is parsed and processed above main. the functions are defined etc. but they are not called. execution begins after our functions are defined only because there is no main function defined and that is where the first executable code is found.. `valid` is not equal to the function `isValid`, `valid` is equal the result returned from calling the function `isValid`. indeed while it returns false a user will be reprompted ( this is main reason i seperated validation from conversion) Commented Mar 31 at 18:44

So many problems here. Strongly suggest you break the problem into subproblems. This is the way in programming. Writing one big huge long main function is a nono. It's hard to read, it's hard to debug, it's hard to test, annoying to troubleshoot. Also remember you should be building upon the knowledge you learned in the prior exercises and lessons. You've covered functions, conditionals and loops. So put them to use.

Friends don't let friends make blobs.

So how do we go about solving this or any other problem? We break the problem down into the logical steps that must occur at a high level.

1. Get input
2. Determine if input is valid
3. If invalid reprompt ( go to 1 )
4. Convert validated input to output

Ok that seems easy enough... let's make a shell to handle this

``````
def isValid(value):
return isValidComma(value) or isValidSlash(value)

def isValidComma(value):
"""Determines if value is a valid date in comma format"""
# reminder comma format is "month_as_word (D)D, YYYY"
# perform needed checks here
return True #or False as needed

def isValidSlash(value):
"""Determines if value is a valid date in Slash format"""
# reminder slash format is "(M)M/(D)D/YYYY"
# perform needed checks here
return True #or False as needed

def convertFromComma(value):
"""returns proper year, month and day from the comma based value"""
# do stuff
return year, month, day

def convertFromSlash(value):
"""returns proper year, month and day from slash based value"""
#do stuff
return year, month, day

# Main Code

valid = False
while not valid: #3
try:
x = input("Date: ") #1
valid = isValid(x): #2
except ValueError:
valid = False
#end of try block

#while block completed

#now determine which format it is and convert it
#4
if ',' in x:
year, month, day = convertFromComma(x)
else:
year, month, day = convertFromSlash(x)

print(f"{year:04}-{month:02}-{day:02}")
``````

Ok now it's up to you to go implement the functions involved so that it works. Now you have pieces you can individually test, and the code will be much easier to follow.

Feedback from original code problems

Other issues are rampant in your code which is why I strongly suggest you toss it and or restructure it.

For example :
`if len(split_coma) <2 and len(split_coma) > 2:` this can never be true, the length can't simultaneously be less than two and greater than two. Did you mean `or`?

Next you have `if len(split_coma[1]) < 4 or len(split_coma[1]) > 4:` ok except that if there's a space the length will be 5 not 4. so this is going to throw just about everything away and reprompt you.

Next: all of your reprompts occur not just once but twice, you reprompt immediately and then hit the while loop end case and prompt again...

Next: `if months not in split_coma[0]:` this will never be true and can't be true. `months` is a list, the list will not be in `split_coma[0]`.. First you have to split that section into month and date based on space... and then you want to see if the section with the 'month' is in `months`.

Next: There is no need for both `months` and `months_and_number`. just use the second it will be faster.

Next: On the other path you make similar errors `if len(y) < 3 and len(y) > 3:` can't be both at the same time...

Finally you never check in the slash logic that a month number isn't > `12`, and in both paths you never check for `day` being greater than `31`

Strongly suggest you use meaningful variable names as you extract parts of the strings with split. like for example in the slash path you should already have figured out that there are 3 elements. So simply do `raw_month, raw_day, raw_year = x.split(',')`

now you have reasonable variable names to work with and it is clear what the heck is going on. who knows what x and y and split_coma[0] are supposed to be?

Lastly don't worry about the zero padding of the numbers, the string formatting can take care of that, look at the hints.

And finally, the only way out of your loop is to raise an exception that isn't a `ValueError`, but I don't see how one can get raised in your current code. Because you have no breaks to escape the while loop on a valid date.

If this answers your question, please click on the check mark to accept it. Please consider upvoting the answer as well if it was useful. This helps with site maintenance.

• I am deeply sorry for not having replied yet. I have a job in parallel, and have been lacking time lately, I am sorry. But I cannot thank you enough for the many hints and the "structured" skeleton with functions. Commented Mar 20 at 22:41