Time data does not match format YYYY-MM-DD

Viewed 10408

I have an issue getting the difference in days between 2 dates in python.

I have the following block of code:

    last_used = models.DateTimeField(default=datetime.now().date(), editable=False)
    date_format = "%y-%m-%d"
    a = datetime.strptime(str(datetime.now().date()), date_format)
    b = datetime.strptime(str(last_used), date_format)
    days_since_use = models.IntegerField(default=(b-a).days, editable=False)

I have tried with both the %y-%m-%d and YYYY-MM-DD formats but neither worked.

ValueError: time data '2018-09-16' does not match format '%y-%m-%d'

Any ideas?

2 Answers

The year with century (as in 2018, not 18) is denoted with %Y (so an uppercase Y) per documentation.

The format is thus:

%Y-%m-%d

With this format, the datetime.strptime function yields the following result:

>>> datetime.strptime('2018-09-16', '%y-%m-%d')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/lib/python3.6/_strptime.py", line 565, in _strptime_datetime
    tt, fraction = _strptime(data_string, format)
  File "/usr/lib/python3.6/_strptime.py", line 362, in _strptime
    (data_string, format))
ValueError: time data '2018-09-16' does not match format '%y-%m-%d'
>>> datetime.strptime('2018-09-16', '%Y-%m-%d')
datetime.datetime(2018, 9, 16, 0, 0)

As for the ValueError (see comment section). This originates from the fact that you do imperative programming at the class level, which is first of all a huge "code smell" (do not do it, unless you for example want to attach a variable number of methods to a class, and even then it is really bad). The imperative code will only get executed once at the class level: when the class is defined, so for Django that means when you load the server.

If you need to encode the number of days to your model, you can add it to the .save() function:

class SomeModel(models.Model):
    last_used = models.DateTimeField(default=datetime.now().date(), editable=False)
    days_since_use = models.IntegerField(default=0, editable=False)
    def save(self, *args, **kwargs):
        self.days_since_use = (self.last_used.date() - datetime.now().date()).days
        super(SomeModel, self).save(*args, **kwargs)

Note that the .save(..) however can get bypassed. Furthermore the field will not always contain the number of days since that specific day, but only between the days_since_use and the last time it was saved. If you want to calculate the number of days since something happened, it might be better to use a property instead:

code>class SomeModel(models.Model):
    last_used = models.DateTimeField(default=datetime.now().date(), editable=False)

    @property
    def days_since_use(self):
        return (self.last_used.date() - datetime.now().date()).days

I think you need not to use strptime:

class A(models.Model):
     last_used = models.DateTimeField(default=datetime.datetime.now(), editable=False)

obj = A().save()
a = datetime.datetime.now()
b = obj.last_used
difference = a-b # it gives datetime.timedelta object, and make sure that timedelta works only with datetime objects, so you can not use it with dates
# if you want to use with dates first convert them into datetime, then do manipulation and save.

then you can use models.DurationField() to save it

Related