I'm new to python, and have little experience using try & except statements.
My code needs to check the date format entered by user. I'm currently using the code from this thread:
How do I validate a date string format in python?
but it's not working properly:
i.e. the following do not raise an exception, where date_text = "20189901", as does date_text = "20181301"
import datetime
date_text = "20189901"
try:
datetime.datetime.strptime(date_text, '%Y%m%d')
except ValueError:
raise ValueError("Incorrect data format, should be YYYYMMDD")
Is there a way to check date format using a simple if statement?
Related
Application built with: Python and Angular
I have a form that uses the following input to allow a user to insert a date:
<input type="datetime-local" id="clubJoined" name="clubJoined" class="date-input" formControlName="clubJoined">
And in my python backend I convert this string object into a date object using the following:
# - Club Joined
"club_joined": datetime.datetime.strptime(request.form["clubJoined"], '%y-%m-%d %H:%M')
But this gives me a formatting error:
ValueError: time data '2011-01-01T23:36' does not match format '%y-%m-%d %H:%M'
So I added the T so that the conversation format looks like this:
# - Club Joined
"club_joined": datetime.datetime.strptime(request.form["clubJoined"], '%y-%m-%dT%H:%M')
But this gave me the following error:
ValueError: time data '2011-01-01T23:36' does not match format '%y-%m-%dT%H:%M'
How do I format this correctly?
The correct format is "%Y-%m-%dT%H:%M"
%y stands for two-digits year, here you can find full list of format options.
I have code like this:
from datetime import datetime
from tabulate import tabulate
def search_projection_date():
projections = open('projections.txt','r').readlines()
date = input("Input projection date: ")
try:
date = date.strptime(date, "%d.%m.%Y.")
except:
print("Date input error!")
#search_projection_date()
for i in projections:
projections = i.strip("\n").split("|")
if date == projections[2]:
table = [['Code:',projections[0]],['Hall:',projections[1]],['Date:',projections[2]],['Start time:',projections[3]],['End time:', projections[4]],['Day(s):', projections[5]], ['Movie:', projections[6]], ['Price:', projections[7]]]
print (tabulate(table))
#break
else:
print("No projection on that date")
And text file like this:
0001|AAA|17.12.2017.|20:30|21:00|sunday|For a few dolars more|150
0002|BBB|17.12.2017.|19:30|21:15|saturday|March on the Drina|300
0003|GGG|19.12.2017.|18:00|19:00|tuesday|A fistful of Dolars|500
0004|GGG|16.12.2017.|21:15|00:00|sunday|The Good, the Bad and the Ugly|350
I try to search movie projections by date...
If there is a projection on the entered date it will find it and print the list, but before printing that list it will always print "Date input error" and after that list "No projection on that date". (if I put break in if statement it will print only the first found projection on entered day, withouth else statement, obvious)
Questions: How to print ONLY list of projections without "date input error" if date is correctly input.
How to print only "No projection on that date" if date is correct but there is no projection and how to ask user for input that until puts it correctly? In this way with recursion it will always throw exception and recursion search_projection_date() function.
There are a whole bunch of major problems with your code. As it happens, they showcase why some general advice we hear so often is actually good advice.
The line date = input("Input projection date: ") creates a string named date. input always returns a string. Strings in Python do not have a method called strptime. Which brings us to issue #2:
You should not catch generic exceptions. You were probably looking to trap a TypeError or ValueError in the except clause. However, you are getting an error that says AttributeError: 'str' object has no attribute 'strptime'. This is because you can't call methods that you want to exist but don't. Your except line should probably read something like except ValueError:.
Your except clause does nothing useful (beyond the problems listed above). If the string is not formatted correctly, you print a message but continue anyway. You probably want to use raise in the except clause to propagate the exception further. Luckily for you, you actually want the date to be a string, which brings us to issue #4:
Why are you attempting to convert the string to a date to begin with? You can not compare a date object and a string that you get from the file and ever expect them to be equal. You want to compare a string to a string. If you had some kind of validation in mind, that's fine, but use datetime.strptime and don't replace the original string; just raise an error if it doesn't convert properly.
The else clause in a for loop will execute whenever the loop terminates normally (i.e., without a break). Since you always iterate through all the lines, you will always trigger the else clause. You need to have another way to determine if you found matching items, like a boolean flag or a counter. I will show an example with a counter, since it is more general.
You never close your input file. Not a huge problem in this tiny example, but can cause major issues with bigger programs. Use a with block instead of raw open.
Your method of iterating through the file is not wrong per-se, but is inefficient. You load the entire file into memory, and then iterate over the lines. In Python, text files are already iterable over the lines, which is much more efficient since it only loads one line at a time into memory, and also doesn't make you process the file twice.
Combining all that, you can make your code look like this:
def search_projection_date():
counter = 0
with open('projections.txt','r') as projections:
date = input("Input projection date: ")
for line in projections:
projection = line.strip("\n").split("|")
if date == projection[2]:
table = [['Code:',projection[0]],
['Hall:',projection[1]],
['Date:',projection[2]],
['Start time:',projection[3]],
['End time:', projection[4]],
['Day(s):', projection[5]],
['Movie:', projection[6]],
['Price:', projection[7]]]
print(tabulate(table))
counter += 1
if not counter:
print("No projection on that date")
else:
print("Found {0} projections on {1}".format(counter, date))
I trusted your use of tabulate since I am not familiar with the module and have no intention of installing it. Keep in mind that the date verification is optional. If the user enters an invalid string, that's the end of it: you don't need to check for dates like 'aaaa' because they will just print No projection on that date. If you insist on keeping the verification, do it more like this:
from datetime import datetime
datetime.strftime(date, '%d.%m.%Y.')
That's it. It will raise a ValueError if the date does not match. You don't need to do anything with the result. If you want to change the error message, or return instead of raising an error, you can catch the exception:
try:
datetime.strftime(date, '%d.%m.%Y.')
except ValueError:
print('Bad date entered')
return
Notice that I am catching a very specific type of exception here, not using a generic except clause.
Is there a way to get datetime.strptime() to give me a default value on a failed parse (None in this case)? I have user entered data from a file that could be improperly formatted dates. The dates should be in the form mm/dd/yy, but some people have put them dd/mm/yy. So the file could look like this:
user1 01/30/14
user2 02/19/12
user3 27/02/11
I don't need to account for the improperly formatted dates, so I can just return None. I know I can do this with:
try:
return datetime.strptime(row[1], '%m/%d/%y')
except:
return None
But I'd like to have something a little more gracefully. Is anyone aware of a solution here?
Thanks in advance.
The datetime package does not offer a built-in solution to your problem.
A more graceful (close to your suggestion) solution would be to define your own function (for instance, in your utils.py file or equivalent).
from datetime import datetime
def strptime(date_string, format, default=None):
try:
return datetime.strptime(date_string, format)
except (ValueError, TypeError):
return default
The following exception will be raised (you might want to handle other exceptions):
TypeError: In case date_string is not a str (e.g. if you pass None)
ValueError: In case date_string mismatch the format
You could then import your strptime (from your utils for instance) instead of datetime.datetime.strptime.
Is there any way, how to parse line which contains date in some format and value? I'm looking for general solution. I'm writing script, which should validate string. My input is some string and time format. For example:
in first file and known time format
[10:17:21 20.04.1911] 890.584
[%H:%M:%S %d.%m.%Y]
in second file and known time format
10:17:21-20.04.1911 890.584
%H:%M:%S-%d.%m.%Y
in third file and known time format
(20-04-1911) 890.584
(%d-%m-%Y)
in fourth file and known time format
20-04-1911 10:17:21 890.584
%d-%m-%Y %H:%M:%S
etc.
I already have function to get timestamp from date according to time format, but I don't know, how to parse date from that line.
Any ideas? Thanks.
I would use try here:
import datetime
def parse_date(line):
for template, length in [("[%H:%M:%S %d.%m.%Y]", 21),
("%H:%M:%S-%d.%m.%Y", 19), ...]:
try:
return datetime.datetime.strptime(line[:length], template)
except ValueError:
pass
This will work through all the templates, return a datetime object if it can extract one from the line and return None if none of the templates match.
In my form I have a DateField called booking_date that is rendered with the AdminDateWidget. The contents of the booking_date field needs to be internationalized. The problem appears when I want to use the value of the field in something like this:
booking = Booking.objects.get(booking_number='BN34D', booking_date='2010-11-21')
But if my date format is '%d.%m.%Y':
booking = Booking.objects.get(booking_number='BN34D', booking_date='21.11.2010')
I get a 'ValidationError: Enter a valid date in YYYY-MM-DD format'
How can I make the query regardless of the date format used?
You should parse it first with a localized version of the strftime format.
from datetime import datetime
d = datetime.strptime('...')
booking.objects.get(..., booking_date=d.date())
Use these formats in strptime:
http://linux.die.net/man/3/strftime
You shouldn't rely on passing directly from the user into the query.
Looks like you should be doing the following from your specific example:
d = datetime.strptime('%d.%m.%Y')
booking = Booking.objects.get(booking_nmber='BN34D', booking_date=d)
As I understand your question, you don't know for sure in advance, which locale will be used. That can bring you into unsolvable problems. ("10-11-12" could be Oct 11, 2012 or Nov 12, 2010 or ...)
So you must have a limited, distinguishable set of possible formats. Then you can do:
POSSIBLE_FORMATS = ('%d.%m.%Y', '%Y-%m-%d', '...')
for f in POSSIBLE_FORMATS:
try:
d = datetime.date.strptime(date_str, f)
break
except ValueError:
continue
raise ValueError
booking = Booking.objects.get(booking_number='BN34D', booking_date=d)
I have solved the problem using this:
from django.utils import formats
formats.get_format('DATE_INPUT_FORMATS')[0]
This format is then used for parsing the date like xyld showed.