Calculate Business Days in Django Annotate - python

I wanted to calculate business days in Django annotate. For example, if an event was generated 7 days back, and I wanted to know how many business days had passed. As per the example, 7 days includes [Monday - Sunday], and I only wanted to include [Monday - Friday], which means 5 business days. I've done this logic via some pythonic hack, but I wanted to do this in Django annotate() method. So I can filter the results based on business days.
Here is an example of what I've done so far:
table_values = Table.objects.all().annotate(issue_severity=datetime.utcnow() - F("event__created"))
for table in table_values:
date = datetime.now(timezone.utc) - table.issue_severity
dates = (date + timedelta(x + 1) for x in range(table.issue_severity.days))
table.business_days = sum(day.weekday() < 5 for day in dates)

Related

Python function for billing calculation

How to create the python function for the Invoicing app to calculate the dates for different billing / invoice terms.
overall if we provide category name to function, it will return the job_date, start_date(DAYS TO COVER ), end_date(DAYS TO COVER ),
Date format to be returned: "%Y-%m-%dT00:00:00Z"
There are below different categories, first row contains the category name, second row lists the job day / date, third row specifies the start and end date to be returned.
WEEKLY
JOB DATE = SUNDAY
DAYS TO COVER = RECENT LAST 7 DAYS (SUN-SAT)
TWICE_A_WEEK
JOB RUN = THURSDAY OR MONDAY
DAYS TO COVER = MON-WED, THURSDAY-SUNDAY
SEMI_MONTHLY - 1-15, 15-31
JOB RUN ON 16 OR 1
DAYS TO COVER = 1-15 OR 16-31
MONTHLY -
JOB RUN ON 1 OR 16
DAYS TO COVER = 1-31, 16-15
CUSTOM - (GET USER INPUT FOR JOB RUN AND DAYS TO COVER)
Above where OR condition is mentioned in JOB RUN, script will get the most recent JOB RUN date and will return respective start_date, end_date and job_run date.
Can, Someone help me with python code or else simply framing an algorithm, Alternative suggestions are also welcomed!!

Python - Calendar / Date Library for Arithmetic Date Operations

This is for Python:
I need a library that is able to do arithmetic operations on dates while taking into account the duration of a month and or year.
For example, say I add a value of "1 day" to 3/31/2020, the result of should return:
1 + 3/31/2020 = 4/1/2020.
I also would need to be able to convert this to datetime format, and extract day, year and month.
Does a library like this exist?
import datetime
tday = datetime.date.today() # create today
print("Today:", tday)
""" create one week time duration """
oneWeek = datetime.timedelta(days=7)
""" create 1 day and 1440 minutes of time duraiton """
eightDays = datetime.timedelta(days=7, minutes=1440)
print("A week later than today:", tday + oneWeek) # print today +7 days
And the output to this code snippet is:
Today: 2020-03-25
A week later than today: 2020-04-01
>>>
As you see, it takes month overflows into account and turns March to April. datetime module has lots of things, I don't know all its attributes well and haven't used for a long time. However, I believe you can find nice documentation or tutorials on the web.
You definitely can create any specific date(there should be some constraints though) instead of today by supplying day, month and year info. I just don't remember how to do it.

Django filter using two conditions

I am developing a web app using django. Among with other tables, I have a table called GeneralContract, which has issueDate and Expiration Date as date fields.
I want to find out the profit of an insurance agent in my case would get from these contracts between a period. For example, if the date range is 15 January 2015 - 25 February 2015 I would like to filter all GeneralContract objects who are issued ANY year between this period.
(i.e. issueDate__month = Date1.month AND IssueDate.day_gte= Date1.day) AND (IssueDate__month = Date2.month AND IssueDate.day_lte = Date2.day) ??
I tried the following but it is not giving me the results I wanted and I am not sure if I am writing this in the correct syntax or if my logic is wrong.
criterion1 = Q(issuedate__month=date1.month)
criterion2 = Q(issuedate__day__gte=date1.day)
criterion3 = Q(issuedate__month=date2.month)
criterion4 = Q(issuedate__day__lte=date2.day)
criterionA = criterion1 & criterion2
criterionB = criterion3 & criterion4
criterionC = criterionA & criterionB
currentGenProfits = GeneralContract.objects.filter(criterionC, cancelled=False)
Is this the right way of doing this filtering logic?
You can't do that because if date1.day = 5 and date2.day = 4 you will have no result, you must check the month and the date together, syntax is right but logic is wrong.
I may suggest to start by taking the biggest set and then apply filtering on it
Start with filtering between the two month and then remove from the queryset objects which are on the first month but before the min day and remove from the queryset objects which are on the last month but after the max day, i think that can do the job.

Django: Count by day, with 0 for days with no records

I want to get the count of records over 14 days
I'm currently doing:
class Invitation(models.Model):
...
start_date = models.DateTimeField(default=timezone.now)
all_invitations = Invitation.objects.all()
days14 = all_invitations.filter(start_date__range=[today - timedelta(days=7), today + timedelta(days=8)]).annotate(day=TruncDay('start_date')).values('day').annotate(count=Count('id')).values('day', 'count').order_by('day')
However, this does not give me the days for which there are 0 invitations.
How do I achieve that?
However, this does not give me the days for which there are 0 invitations.
You have already grouped on day before calculating the count
....values('day').annotate(count=Count('id'))
So these days will only be the ones which are present in the table and hence it doesn't include the days with 0 invitations.
I am not sure if this can fully be achieved through a query because the days you want are not present in the table. You could however do following:
get all the days in 14 days range in a set (s1)
get the days which are present in table within that 14 days range in another set (s2)
take the set difference of s1 and s2.

Applying an arbitrary sort to Django ORM querysets

I have a database table containing sets of items representing yearly recurring events. The record sets are stored by month and day. I often need to retrieve the event records corresponding to a range of calendar dates. I'm using the Django ORM to work with the records, so at present I convert the dates to corresponding Q objects (e.g. Q(month=month, day=day) and OR them together in the call to MyModel.objects.filter().
The problem comes if my date range intersects the new year. If I want the events from Dec. 31, 2013 to Jan 1, 2014, I do something like:
MyModel.objects.filter(Q(month=12, day=31) | Q(month=1, day=1))
But I get my results in the order:
month = 1, day = 1
month = 12, day = 31
Instead, I would like to get my results in the order:
month = 12, day = 31
month = 1, day = 1
For reasons that would unnecessarily complicate the question, I can't simply partition the query into two queries, one for each year. I would like to make one query and get the results in the desired order. I can reformulate the query, if necessary.
I know that extra should be useful, but I don't quite see how to use it.
Update:
To head a little closer to the intended solution, to impose an absolute ordering I could somehow slip the Julian Day into the results as a "calculated" field, and order by that field. But how to do that?
I have tricky solution Using extra and SQL CASE statement:
start_month = 12
start_day = 31
end_month = 1
end_day = 1
query = (models.MyModel.objects.filter(Q(month=start_month, day=start_day) |
Q(month=end_month, day=end_day))
.extra(select={'order_me': '''CASE WHEN month*31+day < %s*31+%s
THEN (12+month)*31+day
ELSE (month)*31+day
END''' % (start_month, start_day)})
.extra(order_by=['order_me']))
As soon as I have added this order_me field (which is not nice) I think It should be used in predicate instead of Q(...)|Q(...) for date range
query = (models.MyModel.objects.all()
.extra(select={'order_me': """CASE WHEN month*31+day < %s*31+%s
THEN (12+month)*31+day
ELSE (month)*31+day
END""" % (start_month, start_day) })
.extra(order_by=['order_me'])
.extra(where=['order_me < (12 + %s) * 31 + %s' % (end_month,
end_day)]))

Categories