How to validate that a string is a valid date in Python - python

I have a model in Django that has two DateFields, but sometimes they receive wrong dates from the front-end, like '20196-10-23'. Even when it might actually be a valid date (crazy, but legit), python doesn't allow to compare both dates due to this error: TypeError: '>=' not supported between instances of 'datetime.date' and 'str', so I want to use clean() method to verify that both dates are valid ones, but I always get dates wrong, even when they are correct.
This is the code for clean() method:
def clean(self, *args, **kwargs):
try:
Reservation.objects.get(booking=self.booking)
except:
pass
else:
raise CustomValidation(_('Booking already exists.'), 'booking', status_code=status.HTTP_400_BAD_REQUEST)
print("{}/{}".format(self.arrival_date, self.departure_date))
try:
datetime.strptime(self.arrival_date, "%Y-%m-%d")
except:
raise CustomValidation(_('Arrival date must be a valid date.'), 'arrival_date', status_code=status.HTTP_400_BAD_REQUEST)
if self.arrival_date >= self.departure_date:
raise CustomValidation(_('Departure date must be later than Arrival date.'), 'departure_date', status_code=status.HTTP_400_BAD_REQUEST)
elif self.arrival_date <= timezone.datetime.now().date():
if self.id == None:
raise CustomValidation(_('Arrival date must be later than today.'), 'arrival_date', status_code=status.HTTP_400_BAD_REQUEST)
if self.status == 'CONFIRMED' and self.confirmation is None:
raise CustomValidation(_('Must provide a confirmation number.'), 'confirmation', status_code=status.HTTP_400_BAD_REQUEST)
I always get an exception, even when the date is correct.

While 20196 is conceptually a valid year, Python won't allow it. I tried this...
import datetime
from datetime import date
def clean(arrival_date):
return date(*map(int, arrival_date.split("-")))
print(clean("20196-10-23"))
# ValueError: year is out of range
...and found out there's actually a hard-coded maximum year value of 9999 for Python dates.
So while you could technically validate the format in various ways, you won't be able to handle dates like this with the built-in datetime module.

I usually first set both dates as datetime.strptime():
try:
#get the dates
my_date_time_1 = self.cleaned_data['date_1']
my_date_time_2 = self.cleaned_data['date_2']
#set the datetime
my_date_time_1 = datetime.strptime(my_date_time_1, '%Y-%m-%d %H:%M:%S')
my_date_time_2 = datetime.strptime(my_date_time_2, '%Y-%m-%d %H:%M:%S')
except:
raise forms.ValidationError(u'Wrong Date Format')
#and then compare dates
if my_date_time_1 >= my_date_time_2:
raise forms.ValidationError(u'Please check the dates')

Related

How do I check date of birth format is correct

I'm currently coding an account signup on python and I need the user to enter their date of birth in the format DD/MM/YYYY.
How would I be able to check in the code if the input is valid or not?
dob=input("Enter your date of birth in the format DD/MM/YYYY")
import datetime
try:
date_of_birth = datetime.datetime.strptime(dob, "%d/%m/%Y")
except:
print("Incorrect date!")
Use following code
from datetime import datetime
i = str(raw_input('date'))
try:
dt_start = datetime.strptime(i, '%d/%m/%Y')
except ValueError:
print "Incorrect format"
Try using the datetime library
from datetime import datetime
def validate(date_text):
try:
datetime.datetime.strptime(date_text, '%d/%m/%Y')
except ValueError:
raise ValueError("Incorrect data format, should be YYYY-MM-DD")

My date in being transformed to UTC?

I got this function below which helps me to change a date format from one to another:
def change_time_format(self, date_string, input_format, output_format):
if date_string == None:
return None
try:
date = datetime.datetime.strptime(date_string, input_format)
timestamp = calendar.timegm(date.timetuple())
new_formatted_date = datetime.datetime.fromtimestamp(timestamp).strftime(output_format)
return new_formatted_date
except Exception as E:
print E
return None
And when i'm calling it like this:
dtu.change_time_format('2017-01-01 12:34:56', '%Y-%m-%d %H:%M:%S', '%d%m%Y %H%M%S')
I'm getting the input as:'01012017 153456' which is wrong and needs to be: '01012017 123456', there is a difference of 3 hours for some reason.
I can't find how to fix it, I searched for several ways over the web and I couldn't find nothing.
From here:
return datetime.datetime.strptime(date_string, input_format).strftime(output_format)

Django: TypeError: 'datetime.date' object has no attribute 'get'

I have TransactionForm as follows:
class TransactionForm(ModelForm):
start_date = forms.DateField(widget=SelectDateWidget)
duration = forms.ChoiceField(choices=duration_choices)
class Meta:
model=Transaction
fields=(
'start_date',
'duration',
)
def clean(self):
date = self.cleaned_data.get("start_date")
if date < datetime.date.today():
raise forms.ValidationError("The date cannot be in the past!")
return date
It has a method clean which checks if date entered is at least todays or greater. When some date in past is inserted it shows error on remplate as expected. But when a valid date is entered, I get the following error.
'datetime.date' object has no attribute 'get'
Here is my view.py file
def packages(req):
if req.method == 'POST':
form = completeForm(req.POST)
tf = TransactionForm(req.POST)
if tf.is_valid():
return HttpResponse("Some page")
else:
errorList = tf.errors['__all__']
args={'form':form, 'errors':errorList, 'tf':tf}
return render(req,'main/common/packages.html',args)
else:
form = completeForm()
tf = TransactionForm()
args={'form':form, 'counter':1, 'tf':tf}
return render(req,'main/common/packages.html',args)
If I remove clean method from form it works fine but I need to validate date without using JavaScript validation.
I found this question closest to mine but its solution is not working or me. Could you please what am I doing wrong?
You don't validate over multiple fields, thus I suggest trying this instead of def clean(self):
def clean_start_date(self):
st_date = self.cleaned_data.get("start_date")
if st_date < datetime.date.today():
raise forms.ValidationError("The date cannot be in the past!")
return st_date
Edit: If you did try to validate over multiple fields, that would be the case when documentation suggests using custom clean function.

Checking if dictionary contains the date and plan

So I am trying to create a function that checks whether or not the contents of a function is true:
def command_add(date, event, calendar):
'''
Add event_details to the list at calendar[date]
Create date if it was not there
:param date: A string as "YYYY-MM-DD"
:param event: A string describing the event
:param calendar: The calendars database
:return: a string indicating any errors, "" for no errors
'''
>>> calendar == {'2015-10-20': ['Python']}
True
>>> command_add("2015-11-01", "Computer Science class", calendar)
''
How would I write such a function? The problem I'm having is how to make the string or how to see if the string for the date is in the format 'YYYY-MM-DD'.
The following code uses strptime to parse the date, if the parsing fails it is not a proper date string. Then it checks if the date is already in the calendar dict or not to see whether to append or add the first entry.
from datetime import datetime
def command_add(date, event, calendar):
'''
Add event_details to the list at calendar[date]
Create date if it was not there
:param date: A string as "YYYY-MM-DD"
:param event: A string describing the event
:param calendar: The calendars database
:return: a string indicating any errors, "" for no errors
'''
try:
datetime.strptime('%Y-%m-%d', date):
except ValueError:
return 'Error parsing date'
else:
if date in calendar:
calendar[date].append(event)
else:
calendar[date] = [event]
return ''
Look at: https://docs.python.org/2/library/time.html#time.strptime
Give strptime the wanted format and if string is not formatted as you wanted you will get an exception
from datetime import datetime
def command_add(date, event, calendar):
# Your Code
calendar = {'2015-10-20': ['Python']}
try:
Date = "2015-11-01"
date_object = datetime.strptime(Date, '%Y-%m-%d')
command_add(Date, "Computer Science class", calendar)
except:
print "Date Format is not correct"

django internationalizing a calendar and using single character day name

I have two questions, I've recently built a django custom templatetag which displays a calendar when called. Am currently facing two issues which am not sure how to resolve,
How do I display day names as single character (S, M, T,..etc) I found calendar.day_abbr which returns (SAT, MON..etc)
My site is being used on several languages and I was wondering how do I get them to display as per viewing language. I tried using LocaleTextCalendar() but without any luck.
from django import template
import calendar
from django.conf import settings
register = template.Library()
def calendar_parser(parser, token):
"""
calendar parser will handle validating the parameters and passing them on to the context
"""
try:
tag_name, year, month, entries, as_, resolve_tag = token.split_contents()
except ValueError:
raise template.TemplateSyntaxError, "%r tag requires six arguments" % token.contents.split()[0]
return calendar_node(year, month, entries, resolve_tag)
class calendar_node(template.Node):
"""
Process a particular node in the template. Fail silently.
"""
def __init__(self, year, month, entries, resolve_tag):
try:
self.year = template.Variable(year)
self.month = template.Variable(month)
self.entries = template.Variable(entries)
#resolved strings
self.resolve_tag = resolve_tag
except ValueError:
raise template.TemplateSyntaxError
def render(self, context):
try:
# FIRST_DAY_OF_WEEK beginning of the week, django setting
cal = calendar.LocaleTextCalendar(settings.FIRST_DAY_OF_WEEK, 'ar')
# render calendar header
context['week_header'] = [day for day in calendar.day_name]
# Get the variables from the context so the method is thread-safe.
my_entries = self.entries.resolve(context)
my_year = self.year.resolve(context)
my_month = self.month.resolve(context)
month_days = cal.itermonthdays(my_year, my_month)
lst = [[]]
week = 0
# make month lists containing list of days for each week
# each day tuple will contain list of entries and 'current' indicator
for day in month_days:
entries = current = False # are there entries for this day; current day?
lst[week].append((day, my_entries, current))
if len(lst[week]) == 7:
lst.append([])
week += 1
# assign variable to context as resolve_tag
context[self.resolve_tag] = lst
return ''
except ValueError:
return
except template.VariableDoesNotExist:
raise template.TemplateSyntaxError
Register the template tag so it is available to templates
register.tag("calendar_view", calendar_parser)
calendar.weekheader(n)
Return a header containing abbreviated weekday names. n specifies the width in characters for one weekday.
Thus for n=1 will return single character abbreviations.

Categories