python - how do I find two desired integer values in a variable? - python

I'm in the process of learning how to code in Python and have been doing numerous tasks to help solidify info.
I had 1 issue - I am creating code that will take the date (dd/mm/yyyy) and then the program will validate the data (i.e checking if there are errors in the field and if so, naming the error type; if no errors are found, the user is told the input was correct) - just some data validation practise.
Where I'm getting stuck is just assigning the variables - I have typed and tested the day and year correctly but I cant manage to get the 4th and 5th integer of the variable date for the month variable.
Here is my code that I am first producing to make sure the integers I will be working with are correct:
date = input("Please enter the date in format dd/mm/yyyy: ")
valid_characters = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ/-'
#defines where to locate day in user input
dayDate = str(date)[:2]
# could also be written as dayDate = str(date)[:-8]
#defines where to locate month in user input
def month(date):
return date[(len(date)//2)]
finalMonth = month(date)
#defines where to locate year in user input
yearDate = str(date)[-4:]
print(yearDate)
print(finalMonth)
print(dayDate)
From this code, the variables yearDate and dayDate present me with the values I want but the finalMonth is where i'm getting stuck. I've looked all over Google but can't seem to find the solution. If you do know how to solve my issue, I would really appreciate it if you could send the proper way to go about this and why you did what, as I am still kind of a newb in Python :)
I know the error is the function I've created for finding the month values, but that's precisely where I need help.
Thank you!
EDIT:
Sorry! I am new to Stack overflow so I didn't know.
so the code:
def month(date):
return date[(len(date)//2)]
finalMonth = month(date)
print(finalMonth)
returns the output '/' but what I am trying to get is for example you input '26/01/2021' and the variable finalMonth will give '01' - this code produces '/'. I am not sure what method should be used to get the month value.

you can use split() to create a list from input as below
date = input("Please enter the date in format dd/mm/yyyy: ")
valid_characters = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ/-'
#defines where to locate day in user input
day, month, year = date.split("/")
print( day, month, year )

The quick answer to your error you were having is change
date[(len(date)//2)] to date[3:5]
After your clarification, I put together an example showing how you can handle error checking. :)
import datetime as dt
# the -> is to hint at the type of variable this function will return, this is not needed, but good practice
def get_date_from_user() -> dt.datetime:
# This will keep looping until correct gets changed to True
correct = False
while correct is False:
user_input = input("Please enter the date in format dd/mm/yyyy: ")
try:
# This part can be done in a lot of ways, I did it this way to demonstrate a condensed way and type conversions
date = dt.datetime(int(user_input[-4:]), int(user_input[:2]), int(user_input[3:5]))
correct = True # If the datetime was made successfully, set the loop to TRUE to escape
except ValueError as err:
print(err)
return date
date = get_date_from_user()
print(f'Day: {date.day} Month: {date.month} Year: {date.year}')
For handling dates though I highly recommend checking out Pendulum. With it you could do something like this:
import pendulum
date = pendulum.parse(input("Please enter the date in format dd/mm/yyyy: "))
dayDate = date.day
finalMonth = date.month
yearDate = date.year
It will throw an error if it cant parse what they typed in as well. If you wrap it in a Try and Except cause you can catch that too like below:
Python error handeling
import pendulum
try:
date = pendulum.parse(input("Please enter the date in format dd/mm/yyyy: "))
except ValueError as err:
print(err)
dayDate = date.day
finalMonth = date.month
yearDate = date.year

Related

Is there a function to 'autocomplete' a variable to a desired library?

I'm trying to set a variable to one I have in a library. Is there a command to do this?
I'm trying to make a simple time zone converter and I want to check the input variable, but I can only check the variables in the list from pytz so I want to 'autocomplete' the variable. can I do this?
import time
import pytz
country = input("enter country")
from datetime import datetime
from pytz import timezone
fmt = "%H:%M %p"
now_utc = datetime.now(timezone('UTC'))
print (now_utc.strftime(fmt))
from pytz import all_timezones
if country in all_timezones:
country = #completed country in list 'all_timezones'
timecountry = now_utc.astimezone(timezone(country))
print (timecountry.strftime(fmt))
So what you are looking for is a way to match the user input to the strings in all_timezones and look for a valid timezone.
As far as I know, there is no built-in function that does it, you have to do it by yourself.
It's not an immediate task, as you may have multiple options (let say the user inputs just 'Europe') and you have to take this in consideration
A possible way to do is the following:
import datetime
import time
import pytz
country = input("Contry name: ")
now_utc = datetime.datetime.now(pytz.timezone('UTC'))
fmt = "%H:%M %p"
while True:
possible_countries = [ac for ac in pytz.all_timezones if country in ac]
if len(possible_countries) == 1:
cc = possible_countries[0]
timecountry = now_utc.astimezone(pytz.timezone(cc))
print(timecountry.strftime(fmt))
break
elif len(possible_countries) > 1:
print("Multiple countries are possible, please rewrite the country name")
for cs in possible_countries:
print(cs)
country = input("Contry name: ")
else:
print("No idea of the country, here are the possible choices")
for cs in pytz.all_timezones:
print(cs)
country = input("Contry name: ")
With a list comprehension I look for all the strings in all_timezones which contains the user input. If there is just one, the script assumes that is the correct one and perform the task. Otherwise if there are multiple possibilites it prints them (one per row with the for loop, but you may just print the list so its shorter on the screen) and then asks the user to rewrite the country name. If there is no match, it just print all the possibilites. You may find it ugly to see on the command line, but you should get the idea and then improve it.
If you wish to check also for spelling errors in the user input... that is a lot more difficult.

Any way of returning 2 objects from a function without making a tuple?

I am making a basic date converter and I need to update the the date every time the user enters an invalid date and is asked to input again. From this function below, I need both the object day and year returned.
def day_valid (month, dates, feb_day, month_days):
day = int(dates[2:4])
while month_days == 31 and day > 31:
print ("Invalid day input.")
print()
dates = input_date()
day = int(dates[2:4])
if month_days == 31 and day < 32:
break
while month_days == 30 and day > 30:
print ("Invalid day input.")
print()
dates = input_date()
day = int(dates[2:4])
if month_days == 30 and day < 31:
break
while month_days == feb_day and day > feb_day:
print ("Invalid day input.")
print()
dates = input_date()
day = int(dates[2:4])
if month_days == feb_day and day <= feb_day:
break
return day
When a user types in 00102002 in MMDDYYYY format, there is no month. So the user is prompted to enter again, entering 01102005. The code still displays the date as 10 January 2002 and not 2005 .
If any one needs clarification on the code, please ask!
My main function:
def main():
loop = "Y"
print()
print("Welcome to Date Converter!")
print()
while loop.upper () == "Y" :
dates = input_date()
year = int(dates[4:])
month = month_valid(dates)
feb_day = feb_days(year)
month_days = month_Days(month, feb_day)
day = day_valid(month, dates, feb_day, month_days)
month_str = month_names(month)
print()
print("The date is " + str(day) + " " + month_str + " " + str(year))
loop = str(input ("Do you want to re-run this program? Y/N: "))
main()
This sounds first of all like an XY Problem: someone wants to do X, and comes up with a solution requiring doing Y. They need help with Y, so request help to do Y. However, it turns out that Y is not an appropriate solution. By recognizing the XY Problem and asking how to do X instead, the person gets better help and more insight into X.
XY Problems also often look suspiciously like homework problems, since those are often of the form "write a program that does X, by doing Y".
It's OK to pose a question that you want to do X and tried to solve it using Y.
Anyway, that's why you're probably going to get low-effort answers. I'll make the effort :)
Anyway, going with the Y question :)
There is a readability practice that considers tuples harmful because you don't know what the purpose of the items in the tuple are. Consider instead creating an object that holds the things, each with its own attribute, and then return that.
Since you stated that you needed day and year returned:
class DayAndYear(object):
def __init__(self, day, year):
self.day = day
self.year = year
And that's how you do it without making a tuple, and it increases the readability of your program, such as it is.
Now, going with the unstated X question:
without knowing what month_valid does,
assuming feb_days returns the number of days in February of the given year,
assuming month_Days returns the number of days in the given month when it isn't February,
it seems that you want a function that will check if a string is a valid MMDDYYYY string.
def is_valid_date(s):
"""Checks if the given date is a valid MMDDYYYY string.
Args:
s (str): A date to check.
Returns:
bool: True if the date is valid, False otherwise.
"""
if len(s) != 8:
return False
try:
date = int(s[:2])
month = int(s[2:4])
year = int(s[4:])
except ValueError:
return False
if month < 1 and month > 12:
return False
if month == 2:
days_in_month = days_in_february(year)
else:
days_in_month = days_in_month(month)
return date >= 1 and date <= days_in_month
def print_date(s):
"""Prints the given MMDDYYYY date, assuming it has already been checked for validity.
Args:
s (str): A date to print.
"""
print("The date is {:d} {:s} {:d}.".format(
int(s[2:4]), month_name(int(s[:2])), int(s[4:])))
I'd like to highlight a few general techniques to make your programs read better:
We don't know X. A well-posed question is one with specifications for the input and output of the program.
I've used verbose, readable function names.
I've used function comments, complete with args, arg types, and return values so there's no guessing about what things do.
I've chosen a split between checking validity and printing an already valid string. You can combine them. You can also return a string rather than print the date, and return instead the sentinel value None if the date was not valid.
Don't compute any more than you have to. Note the early returns.
No doubt there are library functions that will do this, but I've assumed you don't want to use any library functions.
The short key concepts:
Readability: Programs should be almost as easy to read as prose in your native language.
Readability: Function names should be descriptive.
Readability: Comment your code.
Readability: Choose a consistent format for functions and stick with it ("month_Days" vs "feb_days")
Efficiency: Return early.
Testability: Specify well what your program does in terms of inputs and outputs, give examples of good and bad inputs.
Effectiveness: Use library functions.
Stackoverflowness: Consider if your problem is an XY problem.

How to validate time format?

This is what I have so far, it probably is completely junk. What I want to do is validate caminput1, so that the format is HH:MM:SS.
The hashes are from when I was testing.
def cameraspeedcheck():
timeformat = ("%H:%M:%S")
caminput1 = input("At what time did sensor 1 actuate? ")
# is caminput1 = time(HH:MM:SS)
# time.strptime(caminput1[%H:%M:%S])
caminput1.strptime(timeformat)
# else cameraspeedcheck()
I am not very experienced with the syntax of all this stuff, or coding in general, but before you tell me to go and look it up.
I have been looking around for ages, and I cannot find anything that explains the whole process.
strptime is a class-method of datetime.datetime which accepts the string to parse as first argument and the format as the second argument. So you should do -
def cameraspeedcheck():
timeformat = "%H:%M:%S"
caminput1 = input("At what time did sensor 1 actuate? ")
try:
validtime = datetime.datetime.strptime(caminput1, timeformat)
#Do your logic with validtime, which is a valid format
except ValueError:
#Do your logic for invalid format (maybe print some message?).

How can I make raw_input tolerance more robust in Python 2.7?

I'm new here and to programming so please take it easy. I understand that almost anybody reading this knows more than I do and that I'm probably doing it wrong.
That being said, this is what I'm trying to do:
while True:
arrival = raw_input('Arrival time? Example 8:30 \n')
if arrival != "%s%s:%s%s" % (range(0, 1), range(0, 10), range(0, 7), range(0, 10):
arrival = raw_input('Follow the example: 8:30 \n)
break
elif arrival == "q":
print "escape velocity reached!!!"
return 0
The "if" statement doesn't have proper syntax and I don't even know if this is how one should/would go about writing this code in the first place. Basically, I would like the user input to be in the format 1:11 or 11:11, or my code breaks. Please ignore elif, its just there to break the loop while I'm testing.
Main question:
How can I fix this code or the implement the idea behind this code?
Related questions:
How can I get python to accept many different possible combinations of "properly" formatted strings (XX:XX or X:XX)?
What is a better way to coerce somebody into inputting data within a range of tolerance in a specific format or increase raw_input tolerance?
What is a better way to do all of the above or is there a better way to approach this problem?
Thank you in advance!
p.s.
I know that the only way to get a good answer is to ask a good question... Any tips on better question formatting appreciated as well.
Here's how I would do this:
Use time.strptime to parse the time. A format string of '%H:%M' works OK for
your example, you could get more specific or try to support multiple formats
if you need to.
Use try/except to deal with input that can't be parsed properly. strptime will raise
a ValueError if the format doesn't match, so you use except to deal with that
Set the time_ok flag to True (and therefore exit the while loop) once we've got a time that can be parsed.
Code:
import time
time_ok = False
while not time_ok:
arrival = raw_input('Arrival time? Example 8:30 \n')
if arrival == 'q':
print("Exiting.")
break
# Try to parse the entered time
try:
time_data = time.strptime(arrival, '%H:%M')
time_ok = True
# If the format doesn't match, print a warning
# and go back through the while loop
except ValueError:
print('Follow the example: 8:30 \n')
hours, minutes = time_data.tm_hour, time_data.tm_min
print(hours, minutes)
If I'm understanding you right you want people to enter a time from 0:00 to 11:59. All you have to do is something like the following
while True:
arrival = raw_input("Please enter a time in the format hr:min (such as 8:30)")
if ":" not in arrival:
print("Please enter a time in the format hour:minute")
continue
else:
arrival_list = arrival.split(":")
if (int(arrival_list[0]) not in range(12)) or
(int(arrival_list[1]) not in range(60)):
print("Please enter a valid hour from 0-12 and a valid minute from 0-59")
else:
break
This will keep your loop going until you have a properly formatted time given as an input.
From an overall, general programming point of view I think using the time module is probably better, but I tried to keep this to what I estimated was your skill level.
You will want to use regular expressions to match the input:
import re
format_ok = False
while format_ok:
arrival = raw_input('Arrival time? Example 8:30 \n')
if re.match("\d{1,2}:\d{2}", arrival):
#string format is OK - break the loop
format_ok = True

Regex is not validating date correctly

def chkDay(x, size, part):
dayre = re.compile('[0-3][0-9]') # day digit 0-9
if (dayre.match(x)):
if (len(x) > size):
return tkMessageBox.showerror("Warning", "This "+ part +" is invalid")
app.destroy
else:
tkMessageBox.showinfo("OK", "Thanks for inserting a valid "+ part)
else:
tkMessageBox.showerror("Warning", part + " not entered correctly!")
root.destroy
#when clicked
chkDay(vDay.get(),31, "Day")
#interface of tkinter
vDay = StringVar()
Entry(root, textvariable=vDay).pack()
Problem:
Not validating, I can put in a day greater than 31 and it still shows: OK
root (application) does not close when I call root.destroy
Validating date with regex is hard. You can use some patterns from: http://regexlib.com/DisplayPatterns.aspx?cattabindex=4&categoryId=5&AspxAutoDetectCookieSupport=1
or from http://answers.oreilly.com/topic/226-how-to-validate-traditional-date-formats-with-regular-expressions/
Remember that it is especially hard to check if year is leap, for example is date 2011-02-29 valid or not?
I think it is better to use specialized functions to parse and validate date. You can use strptime() from datetime module.
Let the standard datetime library handle your datetime data as well as parsing:
import datetime
try:
dt = datetime.datetime.strptime(date_string, '%Y-%m-%d')
except ValueError:
# insert error handling
else:
# date_string is ok, it represents the date stored in dt, now use it
31 is actually in your regex because [0-3][0-9] is not exactly what you're looking for.
You would better try to cast it to a int and explicitly check its bound.
Else the correct regex would be ([0-2]?\d|3[01]) to match a number from 0 up to 31
In order to limit the values between 1 and 31, you could use:
[1-9]|[12][0-9]|3[01]

Categories

Resources