0

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}")
8
  • 1
    don't use try/except/else.. its a very very very bad practice. and not needed here.
    – UpAndAdam
    Commented Mar 13 at 16:26
  • 1
    add print outs at your decision points and see why you are always prompting again.
    – UpAndAdam
    Commented Mar 13 at 16:27
  • 1
    you never use test_coma?
    – UpAndAdam
    Commented Mar 13 at 16:28
  • 1
    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
    – UpAndAdam
    Commented Mar 13 at 17:09
  • 1
    test_coma is your own variable you create but never use
    – UpAndAdam
    Commented Mar 13 at 17:10

2 Answers 2

1

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}")


19
  • 1
    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)
    – UpAndAdam
    Commented Mar 28 at 21:41
  • 1
    1. Yes you define functions before using them
    – UpAndAdam
    Commented Mar 31 at 18:31
  • 1
    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.
    – UpAndAdam
    Commented Mar 31 at 18:34
  • 1
    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
    – UpAndAdam
    Commented Mar 31 at 18:40
  • 1
    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)
    – UpAndAdam
    Commented Mar 31 at 18:44
1

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.

Let's summarize your problem:

  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.

1
  • 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

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .