Compare a date with a time period - python

I'm currently running a zoo. The user is asked for a valid date, if the given date is between the inaccessible period for a given animal the animal's name will not be printed, but if it is ouside the period it will. How do I do this if the the date and the period are strings and how do I compare if the date is within the inaccessible period?
Here is the code:
def input_date():
while True:
try:
date = input("Enter the date you want to visit us (DD/MM): ")
pattern_date = ('%d/%m')
date = datetime.strptime(date, pattern_date)
except ValueError:
print("Not a valid date, try again")
continue
else:
break
return date
date = input_date()
class animal:
def __init__(self, species, inaccessible):
self.species = species
self.inaccessible = inaccessible
bear = animal("Bear","01/10 - 31/04")
lion = animal("Lion", "01/11 - 28/02")
penguin = animal("Penguin", "01/05 - 31/08")

The datetime module allows for dates to be subtracted, to yield a "delta".
If you subtract your date from the start of the period, and it's before, you know it's outside the range, same with subtracting the end of the period from the entered date.
So all you need to do is
take apart your period strings (hint: string.split does good things!)
convert the end and beginning date strings to dates using the same method you use to enter the dates
calculate the differences between the user-entered date and these boundary dates
check whether they are both positive

If the dates are consistent in the animal, you can inaccessible.split(" - ") to get each date, then do the same you did in the input_date to get the strings to date objects (strptime). Then dates can be compared using operators (>, <, ==).
This will return true if the input date is in between the inaccessible dates (start and end) start_date < input_date < end_date

Convert the inaccessible date strings into datetime objects, similarly to how you did in input_date.
from datetime import datetime
pattern_date = ('%d/%m')
def input_date() -> datetime:
while True:
try:
return datetime.strptime(input(
"Enter the date you want to visit us (DD/MM): "
), pattern_date)
except ValueError:
print("Not a valid date, try again")
class Animal:
def __init__(self, species: str, inaccessible: str):
self.species = species
self._start, self._end = (
datetime.strptime(d, pattern_date)
for d in inaccessible.split(" - ")
)
def is_inaccessible(self, date: datetime) -> bool:
if self._start < self._end:
return self._start <= date <= self._end
else:
return date >= self._start or date <= self._end
animals = [
Animal("Bear", "01/10 - 30/04"),
Animal("Lion", "01/11 - 28/02"),
Animal("Penguin", "01/05 - 31/08"),
]
date = input_date()
available_species = [a.species for a in animals if not a.is_inaccessible(date)]
print(f"Available animals: {', '.join(available_species)}")
Enter the date you want to visit us (DD/MM): 01/06
Available animals: Bear, Lion

Related

Can't figure out why I cannot invalidate an input if it is not YYYY-MM-DD in python

What I'm trying to do is get an input in the YYYY-MM-DD specific format and it will output the amount of minutes someone has lived since their birthdate. But the function "invalidate" only seems to create errors. Without it the code works as long as you input the correct format. I've tried some regex code but haven't been able to make it work either. Also, would it be easier to do this within a class?
import datetime
import inflect
import sys
import re
##class Date:
##def __init__(self, year, month, day):
def main():
birth = input("Birthdate: ")
##birthdate = invalidate(birth)
print(num_to_words(days_between(format_date(birth))) + " minutes")
##def invalidate(x):
#if x != "%Y-%m-d":
#sys.exit("Invalid")
def format_date(e):
year, month, day = map(int, e.split('-'))
date1 = datetime.date(year, month, day)
return date1
def days_between(f):
today = datetime.date.today()
diff = today - f
x = diff.days * 24 * 60
return x
def num_to_words(x):
p = inflect.engine()
words = p.number_to_words(x)
return words
if __name__ == "__main__":
main()
You need to check it with strptime to see if it actually matches the format, not the exact string:
import datetime
def invalidate(x):
# You were missing the % on d
try:
datetime.datetime.strptime(x, r'%Y-%m-%d')
except ValueError:
return False # Or change this to exit
return True # You could return your datetime object here too
>>> invalidate('2022-06-05')
True
>>> invalidate('2022-6-05')
True
>>> invalidate('')
False
>>> invalidate('2022')
False
In your original function, you were checking the exact match of the string:
>>> invalidate('%Y-%m-d') # This was the only thing that would match
>>> invalidate('2022-6-5')
Invalid
Modify your invalidate function to this:
def invalidate(x):
if re.match(r'^\d{4}-\d{2}-\d{2}$', x):
if datetime.datetime.strptime(x, '%Y-%m-%d'):
return datetime.datetime.strptime(x, '%Y-%m-%d')
else:
print("Invalid date")
sys.exit()
else:
print("Invalid date")
sys.exit()
I have modified my code which now has an additional valid date check after valid format check.

my dob code wont recognize days above 12 without triggering my input error text

my first code i have written whilst learning, and have become stuck on one issue.
NAME=str(input("Enter your name: "))
print ("hello",NAME)
from datetime import *
today = date.today()
print("Today: " + today.strftime('%A %d, %b %Y'))
good_value = False
value = ""
while good_value == False:
value = input("Insert Date in format dd/mm/yyyy: ")
try:
datetime.strptime(value, '%m/%d/%Y')
good_value = True
except ValueError:
print("Error: Date format invalid.")
thisYear = today.year
dob_data = value.split("/")
dobDay = int(dob_data[0])
dobMonth = int(dob_data[1])
ÁdobYear = int(dob_data[2])
dob = date(thisYear,dobMonth,dobDay)
if today == date(thisYear,dobMonth,dobDay):
print ("happy bithday", NAME)
else:
print ("its not your birthday, sucks to be you")
when i run the code it will work perfectly unless i type the date being over the 12th, so not breaking the error loop and obviously limiting the dates that can be put into the finished product.
Here
value = input("Insert Date in format dd/mm/yyyy: ")
you are informing user that format should be DD/MM/YYYY, but here
datetime.strptime(value, '%m/%d/%Y')
you are expecting MM/DD/YYYY. In order to repair this replace former using
value = input("Insert Date in format mm/dd/yyyy: ")
and
dobDay = int(dob_data[0])
dobMonth = int(dob_data[1])
using
dobDay = int(dob_data[1])
dobMonth = int(dob_data[0])
Observe that this did worked for values equal or less than 12 as there are 12 months

How to check if a datetime is in %d/%m/%Y AND if its greater than a certain datetime

I'm trying to make it so that it checks if its in the format I want and if its greater than today's date. I want it to ask for input until it gets a right answer but I can't find a way to do so.
while True:
try:
x=dt.datetime.strptime(input(), '%d/%m/%Y')
break
except ValueError:
print(1)
You can use the today class method to get a datetime object representing today's date, and use the > or < operator to compare it to the parsed x:
while True:
try:
x = dt.datetime.strptime(input(), '%d/%m/%Y')
if x > dt.datetime.today():
break
else:
print('before today')
except ValueError:
print('wrong format')
from datetime import datetime, date
while True:
input_ = input('Enter a date -> ')
try:
dt = datetime.strptime(input_, '%d/%m/%Y').date()
except ValueError:
dt = None
today = date.today()
if dt and dt > today:
break
print('All good!')
->
Enter a date -> 12/01/2021
Enter a date -> 18/01/2021
Enter a date -> 25/01/2021
Enter a date -> 14/02/2021
All good!
Customized your existing code to handle - a) Valid Date Check b) Greater than Today's Date condition.
import datetime as dt
while True:
try:
x = dt.datetime.strptime(input(), '%d/%m/%Y')
if x > dt.datetime.now():
print(x)
break
else:
print("Please Enter a Valid Date:")
except ValueError:
print("Invalid Date Format")
My solution;
import datetime as dt
todays_date = dt.datetime.now()
todays_seconds = todays_date.timestamp()
done = False
while not done:
user_input = input(f"Please type a date later that today's date ({todays_date.strftime('%d/%m/%Y')}): ")
try:
x = dt.datetime.strptime(user_input, '%d/%m/%Y')
if x.timestamp() <= todays_seconds:
print("Date must be after today's date")
else:
done = True
except ValueError:
print('Input not understood, please try again')
Gives;
Please type a date later that today's date (30/01/2021): 30/01/2021
Date must be after today's date
Please type a date later that today's date (30/01/2021): 31/01/2021
Process finished with exit code 0

Changing months from str to int for calculation

I need to change months from a string value to a integer value so I can perform a calculation. I am using the datetime library which can give the current date and I need to compare this to a date entered by the user to find the difference between the months in integer form.
import datetime
current_month = datetime.date.today().strftime('%B')
month_join = input('Please enter the month you joined')
month_difference = current_month - month_join
I would like the input to be as a month if possible. If not I will just use:
month_join = int(input('Please enter the month you joined')
It sounds like what you need is a dictionary which relates the name of a month and its numerical value.
import datetime
month_names = ["January", "February", "March", "April",
"May", "June", "July", "August",
"September", "October", "November", "December"]
months = {name : (index + 1) for index, name in enumerate(month_names)}
current_month = datetime.date.today().strftime('%B')
month_joined = input("Please enter the month you joined: ")
month_difference = abs(months[current_month] - months[month_joined])
print(month_difference)
You can also accomplish the creation of the dictionary through use of the calendar module's month_name list attribute.
import datetime, calendar
months = {name : (index + 1) for index, name in enumerate(calendar.month_name[1:])}
current_month = datetime.date.today().strftime('%B')
month_joined = input("Please enter the month you joined: ")
month_difference = abs(months[current_month] - months[month_joined])
print(month_difference)
Probably the strptime method in datetime will be of some use to you. For example:
import datetime
current_month = datetime.date.today().strftime('%B')
month_join = datetime.datetime.strptime(input('Please enter the month you joined'), "%B")
month_difference = current_month.month - month_join.month
But be careful with this - what if the user joined in the previous calendar year? You would end up with a negative value for month_difference.
You would probably be better off actually getting the full month and year the user joined, turn that into a datetime object, subtract it form datetime.today() to get a timedelta object. Then get the month count from that timedelta object.
You may as well leverage the datetime library as much as possible, rather than trying to reinvent the wheel.
This method allows the user multiple chances to enter a correct answer if they mess up the first time. It also checks to make sure that the number is a valid month. You can also add checks to see if the user needs to include the year. IE: if current_month - month_join < 0 ask them for the year.
import datetime
current_month = datetime.date.today().month
month_join = None
while month_join is None:
month_join = raw_input('Please enter the month you joined: ')
if month_join == 'quit':
exit(1)
try:
month_join = int(month_join)
if month_join > 12 or month_join < 1 or not isinstance(month_join, int):
print('Please enter a month value that is from 1 to 12')
month_join = None
except Exception as e:
if isinstance(e, TypeError) or isinstance(e, ValueError):
print('Please enter the month as an integer. IE. May = 5. If you want to close the program type "quit"')
month_join = None
else:
raise e
month_difference = current_month - month_join
print month_difference
Try the monthdelta library.
import datetime
import monthdelta
current_month = datetime.date.today()
year = current_month.year
month_in = input('Please enter the month you joined')
month_dt = datetime.datetime.strptime(month_in, '%B').date()
# Construct new datetime object with current year
month_join = datetime.date(year=year, month=month_dt.month, day=1)
# Reduce year by one if the month occurs later
if month_join > current_month:
month_join = datetime.date(year=year - 1, month=month_dt.month, day=1)
month_difference = monthdelta.monthmod(month_join, current_month)
print(month_difference[0].months)

How To Have User Input Date and Subtract from It

What I want is a user input a selected date, and subtract that date from the current date, and then create a sleep timer according to the results.
from datetime import tzinfo, timedelta, datetime
def ObtainDate():
isValid=False
while not isValid:
userIn = raw_input("Type Date: mm/dd/yy: ")
try:
d1 = datetime.datetime.strptime(userIn, "%m/%d/%y")
isValid=True
except:
print "Invalid Format!\n"
return d1
t = (datetime.now() - d1).seconds
My current current code looks like this, but I cannot figure out how to get d1 and subtract the current date from it.
Since you are importing the class using
from datetime import tzinfo, timedelta, datetime
you are no longer importing the whole datetime module under that name, but individual classes directly into your script's namespace. Therefore your input parsing statement should look like this:
d1 = datetime.strptime(userIn, "%m/%d/%y") # You are no longer
The following will give you the difference in seconds between now and the entered time:
t = (datetime.now() - d1).total_seconds()
And as for the second part, there are many ways to implement a timer. One simple way is
import time
time.sleep(t)
EDIT
Here is the whole thing together:
from datetime import tzinfo, timedelta, datetime
def ObtainDate():
isValid=False
while not isValid:
userIn = raw_input("Type Date: mm/dd/yy: ")
try:
d1 = datetime.strptime(userIn, "%m/%d/%y")
isValid=True
except:
print "Invalid Format!\n"
return d1
t = (ObtainDate() - datetime.now()).total_seconds()
print t
Your code has a few simple errors. This version works (though I'm not sure exactly what you need, it should get you past your immediate problem).
from datetime import datetime
def ObtainDate():
while True:
userIn = raw_input("Type Date: mm/dd/yy: ")
try:
return datetime.strptime(userIn, "%m/%d/%y")
except ValueError:
print "Invalid Format!\n"
t0 = datetime.now()
t1 = ObtainDate()
td = (t1 - t0)
print t0
print t1
print td
print td.total_seconds()
Your main problem was that you were not calling your function. I have also simplified your while loop to an infinite loop. The return statement will break out of the loop unless it raises an error.

Categories