Creating a function that checks if a date is valid - python

one of the revision questions was to create a function that checks if a date is valid or not and return a boolean. We were given the first two lines of the function, as so.
Edit: We are not allowed to use inbuilt functions that do all the work such as date.time
month_names = ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"]
days_in_month = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
Where the days_in_month list contains the maximum day number for the respective months.
Test cases:
is_a_valid_date("January 28 6")) False
is_a_valid_date("January 21")) True
is_a_valid_date(" June 15B ")) False
Code so far:
def is_a_valid_date(date):
month_names = ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"]
days_in_month = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
clean_date = date.split()
clean_date[1:] = ["".join(clean_date[1:])]
a = False
b = False
if clean_date[0] in month_names:
a = True
x = month_names.find(clean_date[0])
else:
a = a
if clean_date[1].isdigit() == True and int(clean_date[1]) <= int(days_in_month[x]):
b = True
else:
b = b
if a == True and b == True:
return True
else:
return False
I'm having trouble figuring out how to create a condition that sees if the date number inputted is <= the respective month's maximum date number if a = True. I tried using .find but it doesn't seem to work on lists and even then I'm not sure I implemented it properly.

You can simplify that condition like this:
def is_a_valid_date(date):
month_names = ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October",
"November", "December"]
days_in_month = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
month, day = date.split(maxsplit=1)
if day.isdigit():
return int(day) <= days_in_month[month_names.index(month)]
return False
Get the name of the month and day from date. Use that name to find days count in days list. Then convert days to int and compare with value from that list. If day can't be converted to int just return False.

I suggest making a dictionary for every max. no. of days per month (eg. days_in_month={January:31,...} and use days_in_month.get(clean_date[0]) instead. so you don't need x also or clean_date[1]

I hope my answer is what you are looking for.
First I have a dictionary that contains all of the months and their max day number values. We check the inputted day value against the inputted month name using the dictionary month_dictionary and get() like this: if day > month_dictionary.get(month):. If the day value is larger than the month's max day value or smaller than 0, than the function returns False and tells you why (which you can delete if you want).
The second function just has a fancy line that makes inputting the date in easier. month, dayRAW = date.split(" ") splits the 1 inputted string into 2 variables, month and dayRAW when the program sees a space in the string. They will then be used in the same way as the first function (after converting the day string into a number, day = int(dayRAW)).
month_dictionary = {"January": 31,
"February": 28,
"March": 31,
"April": 30,
"May": 31,
"June": 30,
"July": 31,
"August": 31,
"September": 30,
"October": 31,
"November": 30,
"December": 31}
def is_a_valid_date_1(month, day):#Input the month with quotes
if day > month_dictionary.get(month):#Finds the corresponding value(number of days) to the month name
print("Day number is too large")
return False
elif day <= 0:
print("Day number can't be zero or smaller")
return False
else:
print("This is a valid date")
return True
def is_a_valid_date_2(date):
month, dayRAW = date.split(" ")#Separates the date string when it sees a space
day = int(dayRAW)#Turns the string into a workable integer
if day > month_dictionary.get(month):#Finds the corresponding value(number of days) to the month name
print("Day number is too large")
return False
elif day <= 0:
print("Day number can't be zero or smaller")
return False
else:
print("This is a valid date")
return True
It also appears mx0 has a condensed version of what I have written. Nice job mate.
I also hope this helps any other passing people :)

Related

How to make a simple family budget calculator

I am making a simple budget calculator and It is a little bit complicated for me as a beginner. I need to add elements to a list through a function and then print an overview of a specific month and a year. It should sum up the money in each category and print it out.
budget=[]
def add_element (day,month,year,money,category):
budget.append(day,month,year,money,category)
def overview (month,year):
add_element(15,10,2022,150,"food")
add_element(16,11,2022,250,"food")
add_element(17,11,2022,300,"living")
add_element(18,11,2022,500,"food")
add_element(19,11,2022,150,"household")
print(overview(11,2022))
I am expecting this outcome:
{"food": 750, "household": 150, "living": 300}
Similar with using defaultdict
from collections import defaultdict
budget = []
def add_element(*row):
budget.append(row)
def overview(month, year):
summary = defaultdict(int)
for d, m, y, money, category in budget:
if m == month and y == year:
summary[category] += money
return summary
add_element(15, 10, 2022, 150, "food")
add_element(16, 11, 2022, 250, "food")
add_element(17, 11, 2022, 300, "living")
add_element(18, 11, 2022, 500, "food")
add_element(19, 11, 2022, 150, "household")
print(overview(11, 2022)) # defaultdict(<class 'int'>, {"food": 750, "household": 150, "living": 300})
you can anytime convert to dict using dict(summary)
The below code should help you with your need.
def add_element(day, month, year, money, category):
budget.append([day, month, year, money, category])
def overview(month, year):
food_total = 0
household_total = 0
living_total = 0
for item in budget:
if item[1] == month and item[2] == year:
if item[4] == "food":
food_total += item[3]
elif item[4] == "household":
household_total += item[3]
elif item[4] == "living":
living_total += item[3]
return {"food": food_total, "household": household_total, "living": living_total}
budget = []
add_element(15,10,2022,150,"food")
add_element(16,11,2022,250,"food")
add_element(17,11,2022,300,"living")
add_element(18,11,2022,500,"food")
add_element(19,11,2022,150,"household")
print(overview(11,2022))

How to pass multiple values from user and search them in a dictionary to return the key

I have this dictionary:
sales = {
"January": 15000, "February": 22000, "March": 12000,
"April": 17000, "May": 81000, "June": 13000,
"July": 21000, "August": 41200, "September": 25000,
"October": 21500, "November": 91000, "December": 21000
}
I want for the user to be able to enter as many values as he or she wants, and then print the key or keys depending on the entered value, if the value is not in the dictionary it has to return "not found".
I have tried using this:
search = int(sys.argv[1])
sales_inv = {v: k for k, v in sales.items()}
if search in sales.values():
for key, value in sales.items():
if search == value:
print(key)
else:
print("not found")
But when I print, it would only search one value, if i want to search for example: 17000 and 13000, it would only return "April".
I think to get multiple arguments, you can iterate through sys.argv starting from index 1 instead just getting sys.argv[1] which will only give the second argument value
import sys
sales = {
"January": 15000, "February": 22000, "March": 12000, "April": 17000, "May": 81000, "June": 13000, "July": 21000, "August": 41200,"September": 25000, "October": 21500, "November": 91000, "December": 21000}
sales_inv = {v: k for k, v in sales.items()}
for search in sys.argv[1:]:
search = int(search)
if search in sales.values():
for key, value in sales.items():
if search == value:
print(key)
else:
print("not found")
I would highly recommend using argparse's ArgumentParser for this. It offers a lot of flexibility out of the box, e.g., the add_arguments()'s nargs argument, which allows to automatically gather arguments passed to the program into a list.
Here's how I would do it:
from argparse import ArgumentParser
SALES = {
"January": 15000,
"February": 22000,
"March": 12000,
"April": 17000,
"May": 81000,
"June": 13000,
"July": 21000,
"August": 41200,
"September": 25000,
"October": 21500,
"November": 91000,
"December": 21000,
}
parser = ArgumentParser()
parser.add_argument(
"sales_numbers",
# Used in help messages.
metavar="SALES_NUMBER",
# Convert the input to integer,
# print an error if non-integer value is passed in.
type=int,
# Gather all arguments in a list,
# print an error if no arguments have been passed in.
nargs="+",
)
args = parser.parse_args()
# Make the list a set, in case of duplicate input.
sales_numbers = set(args.sales_numbers)
for month, value in SALES.items():
if value in args.sales_numbers:
print(month)
# Get a set of numbers that were input but not there.
not_found = sales_numbers - set(SALES.values())
for num in not_found:
print(f"{num} not found")
You can now run it and pass in arguments, e.g.:
$ my_script.py 123
123 not found
$ my_script.py 15000
January
$ my_script.py 21000
July
December
$ my_script.py 21000 15000
January
July
December
$ my_script.py 21000 15000 123 9999
January
July
December
123 not found
9999 not found
If you forget to pass in the argument(s):
$ my_script.py
usage: my_script.py [-h] SALES_NUMBER [SALES_NUMBER ...]
my_script.py: error: the following arguments are required: SALES_NUMBERS
When you pass in something that cannot be converted to an integer:
$ my_script.py abc
usage: my_script.py [-h] SALES_NUMBER [SALES_NUMBER ...]
my_script.py: error: argument SALES_NUMBER: invalid int value: 'abc'
Comes with a handy --help argument:
$ my_script.py --help
usage: sf_args.py [-h] SALES_NUMBER [SALES_NUMBER ...]
positional arguments:
SALES_NUMBER
optional arguments:
-h, --help show this help message and exit
ok I was too late as usual but nevertheless here my attempt (worth 10 minutes of revising sys.arg):
import sys
sales = {"January": 15000, "February": 22000, "March": 12000, "April": 17000, "May": 81000,
"June": 13000, "July": 21000, "August": 41200,"September": 25000,
"October": 21500, "November": 91000, "December": 21000}
search = [int(sys.argv[x]) for x in range(1 , len(sys.argv))]
sales_inv = {v: k for k, v in sales.items()}
for i in search:
if i in sales.values():
for key, value in sales.items():
if i == value:
print(i,' is : ', key)
else:
print(i,"not found")
it is the same #user696969 but dumbest version, using argparse its cooler

Creating attributes of attributes - possible?

I am dealing with monthly data for a number of different data sets (e.g. air temperature, ocean temperature, wind speeds etc), whereby each month and each data set will share similar attributes. I want to be able to initialise and populate these attributes as efficiently as possible. So far I can only think of trying to somehow append new attributes to pre-existing attributes. Is this possible in Python?
For example, let's say I initialise all my monthly variables like the following:
class Data_Read:
def __init__(self, monthly=np.zeros((200,200,40))): #3D data
self.jan = monthly
self.feb = monthly
self.march = monthly
self.april = monthly
self.may = monthly
self.june = monthly
self.july = monthly
self.august = monthly
self.sept = monthly
self.oct = monthly
self.nov = monthly
self.dec = monthly
Then I can create a new data set for each month which will become something like air_temp.jan or wind_speed.june by doing the following:
air_temp = Data_Read()
wind_speed = Data_Read()
These would be the raw data attributes. However I would then like to do some processing to each of these data sets (like de-trending). Is there a way I can create a class (or a new class?) that will generate new attributes like self.jan.detrend. Basically I want to avoid having to write 12 lines of code for every attribute I want to create, and then be able to easily call any "attribute of the attribute" in my data processing functions thereafter.
Many thanks.
Here's an example of how you could store everything internally in a dictionary and still reference the arrays as attributes as well as call functions on arrays by name:
import numpy as np
class Data_Read:
def __init__(self, monthly_shape=(200, 200, 40)): #3D data
months = [
"jan",
"feb",
"march",
"april",
"may",
"june",
"july",
"august",
"sept",
"oct",
"nov",
"dec"
]
self._months = {month: np.zeros(monthly_shape) for month in months}
def detrend(self, month):
# this is a dummy function that just increments
return self._months[month] + 1
def __getattr__(self, name):
if name in self._months:
return self._months[name]
return super().__getattr__(name)
air_temp = Data_Read()
print(air_temp.jan.shape) # (200, 200, 40)
print((air_temp.detrend("jan") == 1).all()) # True
You can also achieve the same result using setattr and getattr because attributes are just stored in a dictionary on the object anyway:
import numpy as np
class Data_Read:
def __init__(self, monthly_shape=(200, 200, 40)): #3D data
months = [
"jan",
"feb",
"march",
"april",
"may",
"june",
"july",
"august",
"sept",
"oct",
"nov",
"dec"
]
for month in months:
setattr(self, month, np.zeros(monthly_shape))
def detrend(self, month):
# this is a dummy function that just increments
return getattr(self, month) + 1

converting an input date into a string?

I want to know how I can convert an input date for example if I enter 01/01/1996, the output would be "1 January 1996", I need to be able to do this for any date that is entered.
I need to use slicing.
Thank you in advance.
inLine = input("please enter a date (dd/mm/yyyy) : ").split(',')
monthNames = ("January", "February", "March", \
"April", "May", "June", \
"July", "August", "September", \
"October", "November", "December" )
month = inLine [:10]
month2 = "month"[:1]
day = inLine
year = inLine[0:2]
year2 = "year"[0:4]
print("this is the date %s %s %s." % (month2, day2, year2))
I don't know why you need split your input when datetime parsing libraries already exist in Python.
>>> from datetime import datetime
>>> datetime.strptime('01/01/1996', '%M/%d/%Y').strftime('%d %B %Y')
'01 January 1996'
This is very simplistic response. You need to go away and learn about arrays, indexing and manipulating them. I also suggest, if this is homework of some kind, you go through and do more examples and look into what happens if, for example, I enter invalid input.
inLine = input("please enter a date (dd/mm/yyyy) : ").split('/')
monthNames = ("January", "February", "March", \
"April", "May", "June", \
"July", "August", "September", \
"October", "November", "December" )
day = int(inLine[0])
month = int(inLine[1])
year = int(inLine[2])
print("this is the date %s %s %s." % (day, monthNames[month-1], year))

difference between two dates python [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 8 years ago.
Improve this question
from datetime import date
future = input("Enter a date(dd/mm/yyyy): ")
daystring = future[0:2]
monthstring = future[3:5]
yearstring = future[6:10]
today = (date.today())
month = date.today().month
year = date.today().year
day = date.today().day
if monthstring == "01" or "03" or "05" or "07" or "08" or "10" or "12":
if daystring > "31":
print("Invalid Date Entered")
if monthstring == "04" or "06" or "09" or "11":
if daystring > "30":
print("Invalid Date Entered")
months = ["Jan", "Feb", "Mar", "Apr", "May", "June",
"Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
daysinmonth = [31, 29, 31, 30, 31, 30, 31, 31, 30,
31, 30, 31]
if future < today or monthstring > "12":
print("Invalid Date Entered")
else:
layout = "%d/%m/%Y"
a = datetime.strptime(future, layout)
b = datetime.strptime(today, layout)
delta = a - b
print ("The difference between the inputted date and todays date is: ",delta.days, "days")
This code is to ask the user to input a date in the future and then the code should use that input and subtract the current date from it.
For example, today is 01/11/2014 and if the user inputs 03/11/2014 the output should be that the difference is 2 days.
However, I'm getting an error every time I input the future date.
import dateutil.parser as parser
import datetime
date1 = parser.parse(input("Enter Date:"))
print( (datetime.datetime.now() - date1).days )
dateutil is very good at parsing natural date strings ...
you will probably need to install dateutil
easy_install python-dateutil
if you want to not use dateutil as mentioned you can use strptime
def get_user_date(prompt="Enter Date:"):
while True:
try:
return datetime.datetime.strptime("%m/%d/%y",input(prompt))
except ValueError:
print( "Invalid Input!" )
this code I think will work in python 3
There are different things to be considered. Try to take in considerations these points
Check if the user is entering right datetime. You can use regular expression to do that. You can use RE module.
mat=re.match('(\d{2})[/](\d{2})[/](\d{4})$', str(future))
You should filter values between 1-12 for months, and between 1-31 for days. Then distinguish between months, and don't forget February in both cases (leap year or no). You can use calender module to check that.
t= calendar.monthrange(int(yearstring), 2) # This is to check if February has 29 or 28 (is leap year or no), you can do that by checking the day number of "datetime.date (int(yearstring), 3, 1) - datetime.timedelta (days = 1)"
Then, compare between two dates, you should use right time format for every date.
a = date.datetime.strptime(future, "%d/%m/%Y").date()
b = date.datetime.strptime(today, "%Y-%m-%d").date()
delta = a-b
Your code would look like:
import datetime as date
import re
import calendar
future = input("Enter a date(dd/mm/yyyy): ")
#eg: future="02/03/2015"
#print future
mat=re.match('(\d{2})[/](\d{2})[/](\d{4})$', str(future))
if mat is None:
print("Invalid Date Entered, try to enter a date in this form(dd/mm/yyyy) ")
else:
daystring,monthstring,yearstring= mat.groups()
today= str(date.datetime.now()).split(" ")[0]
year, month, day = today.split("-")
months = ["Jan", "Feb", "Mar", "Apr", "May", "June","Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
daysinmonth = [31, 29, 31, 30, 31, 30, 31, 31, 30,31, 30, 31]
if int(daystring)>0 and int(daystring)<=31 and int(monthstring)>0 and int(monthstring) <= 12 and int(yearstring)>0:
if monthstring in ["01", "03", "05" ,"07","08","10", "12"]:
if int(daystring) > 31:
print("Invalid Date Entered - Number of days can't exceed 31.")
if monthstring in ["04","06","09","11"]:
if int(daystring) > 30:
print("Invalid Date Entered - Number of days can't exceed 31.")
if monthstring == "02":
t= calendar.monthrange(int(yearstring), 2) # This is to check if February has 29 or 28 (is leap year or no), you can do that by checking the day number of "datetime.date (int(yearstring), 3, 1) - datetime.timedelta (days = 1)"
if int(daystring) !=t: #You forget faberuary
print("Invalid Date Entered - of days can't exceed 28 or 29")
a = date.datetime.strptime(future, "%d/%m/%Y").date()
b = date.datetime.strptime(today, "%Y-%m-%d").date()
delta = a-b # The future - Today ::> to get a positive number
if delta.days >0:
print ("The difference between the inputted date and todays date is: ",delta.days, "days")
else:
print("Date is in the past")
else:
print("Invalid Date Entered")

Categories

Resources