selecting date in date ranges wrong result - python

Following if statement occasionally gives wrong result. any idea why?
if self.start_date <= datetime.datetime.now().date() <= self.end_date:
self._is_current = True
else:
self._is_current = False
return self._is_current

Related

split data in nested json to make some calculations

hoping someone helps me out. I have a nested json file and I'm trying to calculate the age difference between two lines of the file, the start_date and end_date with date format of mm/yyyy only. So I'm trying to split it so I can calculate the year difference between end_date and start_date, if over 10 years, I add to another list.
This is my code below, but it prints an empty list and I don't know how to fix it. Any tips or directions will be appreciated
Oh...I have to use default python libraries so even though pandas will be easier, I can't use it.
remove_card=[]
def datebreakdown(data_file):
expr1 = data_file['Credit Card']['start_date']
expr2 = data_file['Credit Card']['end_date']
breakdown1 = expr1.split('/')
breakdown2 = expr2.split('/')
card_month = int(breakdown1[0]) - int(breakdown2[0])
card_year= int(breakdown1[1]) - int(breakdown2[1])
if card_year >= 10:
return True
elif card_year == 10 and card_year > 0:
return True
else:
return False
for line in data_json: #data_json is name of the json file.
if datebreakdown(data_file) == True:
remove_card.append(data_file)
I think these are the conditions you want:
if card_year > 10:
return True
elif card_year == 10 and card_month > 0:
return True
else:
return False
The first condition should be strictly >, not >=. The second condition should compare the months when the year difference is exactly 10.
Another problem is that you're subtracting the dates in the wrong order. You're subtracting the end from the start, so it will always be negative. So those subtractions should be:
card_month = int(breakdown2[1]) - int(breakdown1[0])
card_year= int(breakdown2[1]) - int(breakdown1[1])
def datebreakdown(data_file):
expr1 = data_file['Credit Card']['start_date']
expr2 = data_file['Credit Card']['end_date']
year1, month1 = expr1.split('/')
year2, month2 = expr2.split('/')
start_date = int(year1) + int(month1)/12
end_date = int(year2) + int(month2)/12
return end_date - start_date > 10
DEMO

Code to check if current time is before due time

I am trying to see if the current hour, time and section is before the due hour, due minute and due section then it should print true otherwise false. My code is not working and ive been working on this for 2 hours
current_hour = 12
current_minute = 37
current_section = "PM"
due_hour = 9
due_minute = 0
due_section = "AM"
if (((current_hour < 9) and (current_hour != 12)) and (current_minute != 0) and current_section):
print("True")
else:
print("False")
Your current code is failing (presumably) because you're using 'and current_section' which will pass True for any value of current_selection.
Using the datetime library makes this quite simple:
from datetime import datetime
due_time = datetime.strptime('9:00AM','%I:%M%p')
curr_time = datetime.strptime('12:37PM','%I:%M%p')
diff_seconds = (curr_time - due_time).total_seconds()
if diff_seconds > 0:
print('False')
else:
print('True')
You can also add dates to make it more robust (see https://stackoverflow.com/a/466376/10475762 for more information on how to use strptime).

defining a function that gives me the distance between 2 dates

enter image description here
I need to write a piece of code that calculates the distance between 2 dates, as shown in the screenshot above^
This is what I put:
def dist2dates(date1,date2):
result= date2[0:2]-date1[0:2],"/",date2[3:]-date1[3:]
return result
res2=dist2dates(1116,1129)
print(res2)
This produces an error that says:
TypeError: 'int' object is not subscriptable
I am not too sure what I am doing wrong. Also, I am not too clear on how to put a date such as "08/16" in the argument? Can someone help me define such a function?
This is the best I could come up with:
import re
def dist2dates(date1,date2):
if re.match(r'^\d{2}\/\d{2}$', date1) and re.match(r'^\d{2}\/\d{2}$', date2):
diff1 = abs(((int(date2[0:2])-int(date1[0:2]))))
diff2 = abs((int(date2[3:])-int(date1[3:])))
result= ("%02d/%02d") %(diff1, diff2)
return result
else:
return "Incorrect format"
res2=dist2dates("11/16","11/29")
print(res2)
Output:
00/13
It always returns the absolute value abs(), so you wont get negative numbers. It also checks if the date string is formatted correctly using RegEx.
=================== Before edit =================
Try this:
def dist2dates(date1,date2):
result= ("%02d/%02d") %(int(date2[0:2])-int(date1[0:2]) ,int(date2[3:])-int(date1[3:]))
return result
res2=dist2dates("10/16","11/29")
print(res2)
Output:
01/13
The inputs to the dist2dates function should be strings not integers.
Cast the strings into integers so you can subtract the numbers.
The nature of this problem is sort of strange since now your year has 360 days, but this structure handles both if the first date is larger or smaller, it works by evaluating the difference in days based on 30 day months then converts them to days and uses zfill to print the output.
def dist2dates(a, b):
a = list(map(int, a.split('/')))
b = list(map(int, b.split('/')))
if b[0] < a[0]:
days = 360 - 30*(a[0] - b[0]) - (a[1] - b[1])
else:
days = 30*((b[0]- 1) - a[0]) + (30 - a[1]) + b[1]
print(days)
tup = divmod(days,30)
mm, dd = tup[0], tup[1]
return f'{str(mm).zfill(2)}/{str(dd).zfill(2)}'
print(dist2dates('03/20', '01/10')) # => 09/20
print(dist2dates('01/12', '05/20')) # => 04/08
why not use datetime module to calculate the timedelta & use the strptime/strftime for formatting?
from datetime import datetime, timedelta
def dist2dates(strdate1,strdate2):
'''format mm/dd, assumes month = 30 days always'''
dtfmt = '%m/%d'
date1 = datetime.strptime(strdate1, dtfmt)
date2 = datetime.strptime(strdate2, dtfmt)
delta = date2 - date1
year = date1.year
month, day = divmod(delta.days, 30)
result = datetime.strftime(datetime(year, round(month), round(day)), '%m/%d')
return result
res = dist2dates('01/16','11/29')
print(res)
# 10/13

Comparing Dates string in Python

I need help with the python function of comparing two dates (string) and return True if date1 is ealier than date2. Here is my code but I'm don't know why it returns True for the test case("2013/10/24", "2013/9/24")
# str, str -> boolean
def dateLessThan(date1,date2):
date1 = date1.split('/')
date2 = date2.split('/')
if date1[0] < date2[0]:
return True
elif date1[0] == date2[0] and date1[1] < date2[1]:
return True
elif date1[0] == date2[0] and date1[1] == date2[1] and date1[2] < date2[2]:
return True
else:
return False
Just use the datetime.strptime class method instead of doing your own parsing.
def dateLessThan(date1,date2):
date1 = datetime.datetime.strptime(date1, "%Y/%m/%d")
date2 = datetime.datetime.strptime(date2, "%Y/%m/%d")
return date1 < date2
Consider using datetime objects (assumed your time format is YY/mm/dd)
from datetime import datetime
def dateLessThan(date1,date2):
datetime1 = datetime.strptime(date1, '%Y/%m/%d')
datetime2 = datetime.strptime(date2, '%Y/%m/%d')
return datetime1 < datetime2
your test fails because of lexicographical comparison of strings. "10" < "9".
Without using datetime or time parsing (which is required when there are complex formats, months names...), it's possible to do something simple since there's only numbers involved (and you have years/month/day, so you're close to the ISO date format where you can compare lexicographically).
Just map the values into integers and convert to lists and let the natural/lexicographical order of lists do the rest:
def dateLessThan(date1,date2):
return [int(x) for x in date1.split('/')] < [int(x) for x in date2.split('/')]

In Python, is there a neater way than this of deciding whether to use gt or gte based on a boolean variable?

I am writing a Python function to pick out objects from a sorted list which have a date stamp within a certain range. The user provides a start and end date. They can leave either of them blank if they want to use the beginning/end of the list as the start/end dates, respectively. If the user provides date(s), they are able to choose whether to include or exclude them. Currently, my function looks like this:
def get_items_in_date_range(all_items, start_date=None, end_date=None,
include_start_date=True, include_end_date=True):
items_in_date = []
for item in all_items:
if start_date and end_date:
if include_start_date and include_end_date:
if start_date <= item.date_stamp <= end_date: #
items_in_date.append(item)
elif include_start_date:
if start_date <= item.date_stamp < end_date: #
items_in_date.append(item)
elif include_end_date:
if start_date < item.date_stamp <= end_date: #
items_in_date.append(item)
else:
if start_date < item.date_stamp < end_date: #
items_in_date.append(item)
...
(I can post the rest of the function if it will help, but it's the same few if statements, tweaked for the absence of start_date and end_date).
My question is: Is there a way of preparing the if statements marked with the # symbol so that the code can be condensed a little? Perhaps in a way analogous to Python string formatting, e.g.
if start_date %op item.date_stamp %op end_date % (op1, op2):
where I can assign op1 and op2 to be < or <= at the beginning of the function.
This is the first question I've ever submitted, so please let me know if there's any other information I can provide to help/clarify. Thank you!
Python operators are available as methods in the built-in operator package.
You may also reduce the complexity of you code by first filtering all items < start_date then all items > end_date.
That gives something like this (untested):
import operator
def get_items_in_date_range(all_items, start_date=None, end_date=None,
include_start_date=True, include_end_date=True):
start_op = operator.ge if include_start_date else operator.gt
end_op = operator.le if include_end_date else operator.lt
filtered_items = all_items
if start_date:
filtered_items = [item for item in filtered_items if start_op(item, start_date)]
if end_date:
filtered_items = [item for item in filtered_items if end_op(item, end_date)]
return filtered_items
One way to remove the need for all the different comparisons is to setup the start and end date in the beginning of your function, and then do only one comparison.
You can leave the start and end date as a special case, or tweak them to fit in the comparison as nutmeg64 did.
def get_items_in_date_range(all_items, start_date=None, end_date=None,
include_start_date=True, include_end_date=True):
if start_date is None:
start_date = MIN_DATE
if end_date is None:
end_date = MAX_DATE
items_in_date = []
for item in all_items:
is_in_range = start_date < item < end_date
is_start = include_start_date and item == start_date
is_end = include_end_date and item == end_date
if is_in_range or is_start or is_end:
item_in_date.append(item)
There is no way to generally generate a Python code (unless a different Python script writes it to a file and that is a bit complicated).
In this case you could do something like:
if include_start_date:
start_date - 1 # assuming you know how to subtract a day from the date
if include_end_date:
end_date + 1 # assuming you know how to add a day to the date
for item in all_items:
if start_date < item.date_stamp < end_date:
items_in_date.append(item)
You can solve this problem using the operator module:
import operator
def get_items_in_date_range(all_items, start_date=None, end_date=None,
include_start_date=True, include_end_date=True):
lower_op = operator.lte if include_start_date else operator.lt
upper_op = operator.lte if include_end_date else operator.lt
if start_date is None:
start_date = <something-really-in-the-past>
if end_date is None:
end_date = <something-nearing-the-universe-entropy-death>
...

Categories