Django: How to get a time difference from the time post? - python

Say I have a class in model
class Post(models.Model):
time_posted = models.DateTimeField(auto_now_add=True, blank=True)
def get_time_diff(self):
timediff = timediff = datetime.datetime.now() - self.time_posted
print timediff # this line is never executed
return timediff
I defined a get_time_diff to get the time difference from the time when the Post is posted up to now, according to the document, the DateTimeField should be able to be converted to datetime automatically, is that correct? Why the print statement is never being run? How can you extract the time difference?
Beside, if you get a time difference, is there an easy way to convert the time difference to an integer, like the number of seconds of the total time.

Your code is already working; a datetime.timedelta object is returned.
To get the total number of seconds instead, you need to call the .total_seconds() method on the resulting timedelta:
from django.utils.timezone import utc
def get_time_diff(self):
if self.time_posted:
now = datetime.datetime.utcnow().replace(tzinfo=utc)
timediff = now - self.time_posted
return timediff.total_seconds()
.total_seconds() returns a float value, including microseconds.
Note that you need to use a timezone aware datetime object, since the Django DateTimeField handles timezone aware datetime objects as well. See Django Timezones documentation.
Demonstration of .total_seconds() (with naive datetime objects, but the principles are the same):
>>> import datetime
>>> time_posted = datetime.datetime(2013, 3, 31, 12, 55, 10)
>>> timediff = datetime.datetime.now() - time_posted
>>> timediff.total_seconds()
1304529.299168
Because both objects are timezone aware (have a .tzinfo attribute that is not None), calculations between them take care of timezones and subtracting one from the other will do the right thing when it comes to taking into account the timezones of either object.

Assuming you are doing this within a template, you can also use the timesince template tag.
For example:
{{ blog_date|timesince:comment_date }}

Your code
timediff = datetime.datetime.now() - self.pub_date
should work to get the time difference. However, this returns timedelta object. To get difference in seconds you use .seconds attribute
timediff = datetime.datetime.now() - self.pub_date
timediff.seconds # difference in seconds.

Just in case you want to put this process in you Django signals. Here's the one that is working for me. Hope this helps!
from django.db.models.signals import pre_save
from django.dispatch import receiver
from .models import YourModel
from datetime import datetime
#receiver(pre_save, sender = YourModel)
def beforeSave(sender, instance, **kwargs):
date_format = "%H:%M:%S"
# Getting the instances in your model.
time_start = str(instance.time_start)
time_end = str(instance.time_end)
# Now to get the time difference.
diff = datetime.strptime(time_end, date_format) - datetime.strptime(time_start, date_format)
# Get the time in hours i.e. 9.60, 8.5
result = diff.seconds / 3600;

Simply we can add the custom property to calculate the time difference with the help #property decorator in that model.
from django.utils import timezone
class Post(models.Model):
time_posted = models.DateTimeField(auto_now_add=True, blank=True)
content = models.TextField()
#property
def time_diff(self):
return timezone.now() - self.time_posted
time_diff will return object of datetime.timedelta
post = Post.objects.get(pk=1) # Post model object
# time diff in seconds.
post.time_diff.seconds
>>> 652
# time diff in days.
post.time_diff.days
>>> 0
Already answered above nicely by Martijn Pieters, just adding #property, and django.utils.timezone to calculate the difference with respective timezone from settings.py

Related

ideas on how to build a function in python django for cellulating hours interval

I am a total beginner starting a project in Django a payroll calculator app. In it my user has workhours with dates form. The function required should calculate (dates, in hour, out hour) and output the value to another (total hours) field.
the restrictions are:
value must be an integer
value can be crossday meaning: giving a worker crossday shift
07.01.2021,08.01.2021/dates, 22:00:00pm/hour in, 06:00:00am/hour out
function must work with Django .models/.datetime
So far I got this code:
def HoursTotalConf(in_time, out_time):
start_dt = dt.datetime.strptime(in_time, "%H:%M:%S")
end_dt = dt.datetime.strptime(out_time, "%H:%M:%S")
return relativedelta(end_dt, start_dt) '
you can directly do operations with two datetime objects, so if you do end_dt - start_dt you will get a timedelta object.
Btw if you are looking to solve the problem within django, instead of using datetime, use timezone in Django. django timezone
from django.utils import timezone
def hours_total_conf(in_time, out_time):
start_dt = timezone.datetime.strptime(in_time, '%H:%M:%S')
end_dt = timezone.datetime.strptime(out_time, '%H:%M:%S')
time_diff = end_dt - start_dt
# round to hour
total_hours = round(time_diff.seconds/3600)
return total_hours
another thing to mention here is that, if you are solving the problem in Django as explained in restriction 3, why not define these two fields as datetime fields so that you don't have to convert it yourself?

DurationField or Timedelta

im having a problem trying to set a duration in my to-do tasks.
i've tried with DurationField and some people told me to try the timedelta in your forms.py but im not quite shure how to pass the difference like (6days) from my two model DateField (start and end).
Models.py
from django.db import models
from datetime import datetime, timedelta
class To_do (models.Model):
task = models.CharField(max_length=150)
topic = models.CharField(max_length=150)
how = models.TextField(max_length=600)
start = models.DateField(default=datetime.today)
end = models.DateField(blank=False)
duration = models.DurationField(default=timedelta)
i'd like to display the difference for the user and after set an alarm for less than 3 days etc.
How do I solve this?
The difference between two date or date/time values is a timedelta.
delta_time = end - start
Or if you need to code a delta-time constant from other numbers
from datetime import timedelta
my_delta = timedelta( days=3, hours=12, minutes=1 ) # half a week plus a minute
Don't use timedelta as the name as the default value if you are importing it! If what you mean to do is to pass a callable to calculate a timedelta, define a function to do that as above, and pass it as the default value.

Django: Get Months since a certain datetime

I'm trying to get the number of months since a model is created.
My Model looks like this:
class Plan(models.Model):
title = models.CharField(max_length=50)
date_created = models.DateTimeField(default=timezone.now)
plan_type = models.IntegerField()
owner = models.ForeignKey(User, on_delete=models.CASCADE)
Now i want to make a method that returns the number of months since the date_created.
Tanks for any help :D
Comparing dates creates a datetime.timedelta object that you can use to get the difference between dates.
from datetime import timedelta
from django.utils.timezone import now
delta: timedelta = now() - plan.date_created
delta.days # Number of days between dates.
You can then use that value to convert it to months or years.
The other alternative would be a bit more complicated, but since DateTimeField returns a datetime.datetime object, you can also access the month number of the original date and compare it against todays date.
e.g.
from django.utils.timezone import now
month_diff = now().month - plan.date_created.month
The problem with the second alternative is that you then have to take into account if they are the same year or not, and if they are not you then have to take that into account when you get the month difference.
You can write a property in your model like
from django.utils import timezone
class Plan(models.Model):
title = models.CharField(max_length=50)
...
#property
def get_month(self):
return self.date_created.month - timezone.now().month
Then you can get the value like this
>>> Plan.objects.first().get_month
4

Find objects with date and time less then 24 hours from now

I have model with two fields:
class Event(models.Model):
date = models.DateField(_(u'Date'))
time = models.TimeField(_(u'Time'))
I need to find all objects where date&time is in 24 hours from now.
I am able to do this when using DateTime field, but I am not sure how to achieve this when fields are separated. Thanks in advance.
For the simple case (not sure if all are simple cases though...), this should do the trick:
import datetime
today = datetime.datetime.now()
tomorrow = today + datetime.timedelta(days=1)
qs_today = queryset.filter(
date=today.date(),
time__gte=today.time(),
)
qs_tomorrow = queryset.filter(
date=tomorrow.date(),
time__lt=tomorrow.time(),
)
qs = qs_today | qs_tomorrow
As you state you can do what you want with a DateTimeField, but now with the separate fields, I understand your issue is how to combine them.
Looking at the docs for DateField - your date variable is a datetime.date instance and similarly for TimeField time is a datetime.time. You can convert these into a datetime.datetime by using combine()
import datetime as dt
datetime = dt.datetime.combine(date,time)
You now have the datetime object as you would have from DateTimeField. You say in the question you can do the 24 hour from now bit from there, although let me know in comments if you need that made explicit.
Caveat I combine will fail where one of the fields is None - you state this can't happen, so I haven't added any error checking or validation of this.
EDIT
It occurs to me that the problem may not be the combination, but adding the calculated field to the Event object. You could look at this Q&A, or this. In summary you define the calculated value in a function in your class and then make it a property - either with a decorator or a function call. There's an example in the docs, adapting for your case:
def _get_datetime(self):
'''Returns a combination of date and time as a datetime'''
return dt.datetime.combine(self.date,self.time)
datetime = property(_get_datetime)
This should behave in the same way as you would expect a DateTimeField to behave.
You can use Q objects to search for "yesterday after current time or today before current time":
from django.db.models import Q
from .models import Event
from datetime import datetime, timedelta
def get_event_during_last_day():
now = datetime.now()
today = now.date()
yesterday = (now - timedelta(day=1)).date()
time = now.time()
query_yesterday = Q(date=yesterday, time__gt=time)
query_today = Q(date=today, time__lt=time)
return Event.objects.filter(query_yesterday | query_today)

allow HH:MM kind of input in a django DateTimeField instead of long format

I have a model like this
class Timer(models.Model):
"""Represents a timing system"""
start_time = models.DateTimeField(default=datetime.datetime.now())
end_time = models.DateTimeField()
and a form that takes this as the model
class JobForm(forms.ModelForm):
class Meta:
exclude = ['slug','author','duration',]
model = Job
Trouble comes in when i want to add some timing info, and by that i mean that i have to enter it in the long format
DD-MM-YYYY HH:MM:SS
the times will be added in real time on the same day as they happen, so the long format looks like a waste of effort, i would rather do it as
HH:MM
i cant use model.TimeField because i will calculate a duration between a start time and the end time, and someone may straddle midnight by timing their sleep or who knows what else.
How would i allow input in HH:MM and have it as datetimefield (eventualy after some effort)? Id like the code to assume the same date as the current date give HH:MM
After looking at the forms documentation, this is what iv decided to do, since i didn't understand #cclerville's suggestion (maybe django is poor?)
here goes:
in my forms.py
class MyDateTimeField(forms.Field):
def to_python(self, value):
# Return an empty list if no input was given.
if not value:
return []
import datetime
today = datetime.date.today()
hhmm = value.split(':')
val= datetime.datetime.combine(datetime.date.today(), datetime.time(int(hhmm[0]),int(hhmm[1])))
return val
and the form itself:
class JobForm(forms.ModelForm):
end_time = MyDateTimeField()

Categories

Resources