Determine if a day is a business day in Python / Pandas - python

I currently have a program setup to run two different ways. One way is to run over a specified time frame, and the other way is to run everyday. However, when I have it set to run everyday, I only want it to continue if its a business day. Now from research I've seen that you can iterate through business days using Pandas like so:
start = 2016-08-05
end = datetime.date.today().strftime("%Y-%m-%d")
for day in pd.bdate_range(start, end):
print str(day) + " is a business Day"
And this works great when I run my program over the specified period.
But when I want to have the program ran everyday, I can't quite figure out how to test one specific day for being a business day. Basically I want to do something like this:
start = datetime.date.today().strftime("%Y-%m-%d")
end = datetime.date.today().strftime("%Y-%m-%d")
if start == end:
if not Bdate(start)
print "Not a Business day"
I know I could probably setup pd.bdate_range() to do what I'm looking for, but in my opinion would be sloppy and not intuitive. I feel like there must be a simpler solution to this. Any advice?

Since len of pd.bdate_range() tells us how many business days are in the supplied range of dates, we can cast this to a bool to determine if a range of a single day is a business day:
def is_business_day(date):
return bool(len(pd.bdate_range(date, date)))

I just found a different solution to this. This might be interesting if you want to find the next business day if your date is not a business day.
bdays=BDay()
def is_business_day(date):
return date == date + 0*bdays
adding 0*bdays rolls forward on the next business day including the current one. Unfortunately, subtracting 0*bdays does not roll backwards (at least with the pandas version I was using).
Moreover, due to this behavior, you also need to be careful since not necessarily
0*bdays + 1*bdays != 1*bdays

There is builtin method to do this in pandas.
For Pandas version <1.0
from pandas.tseries.offsets import Day, BDay
from datetime import datetime
bday=BDay()
is_business_day = bday.onOffset(datetime(2020,8,20))
For Pandas version >=1.1.0 (onOffset is deprecated)
from pandas.tseries.offsets import Day, BDay
from datetime import datetime
bday=BDay()
is_business_day = bday.is_on_offset(datetime(2020,8,20))

Using at least numpy version 1.7.0., try np.is_busday()
start = datetime.date.today().strftime("%Y-%m-%d")
end = datetime.date.today().strftime("%Y-%m-%d")
if start == end:
# added code here
if not np.is_busday(start):
print("Not a Business day")

for me I use an old trick from Excel:
from pandas.tseries.offsets import Day, BDay
def is_bday(x):
return x == x + Day(1) - BDay(1)

Please check this module - bdateutil
Please check the below code using above module :
from bdateutil import isbday
from datetime import datetime,date
now = datetime.now()
val = isbday(date(now.year, now.month, now.day))
print val
Please let me know if this help.

Related

How to plus datetime in python?

I have the program that generate datetime in several format like below.
1 day, 21:21:00.561566
11:19:26.056148
Maybe it have in month or year format, and i want to know are there any way to plus these all time that i get from the program.
- 1 day, 21:21:00.561566 is the string representation of a datetime.timedelta object. If you need to parse from string to timedelta, pandas has a suitable method. There are other third party parsers; I'm just using this one since pandas is quite common.
import pandas as pd
td = pd.to_timedelta('- 11:19:26.056148')
# Timedelta('-1 days +12:40:33.943852')
td.total_seconds()
# -40766.056148
If you need to find the sum of multiple timedelta values, you can sum up their total_seconds and convert them back to timedelta:
td_strings = ['- 1 day, 21:21:00.561566', '- 11:19:26.056148']
td_sum = pd.Timedelta(seconds=sum([pd.to_timedelta(s).total_seconds() for s in td_strings]))
td_sum
# Timedelta('-1 days +10:01:34.505418')
...or leverage some tools from the Python standard lib:
from functools import reduce
from operator import add
td_sum = reduce(add, map(pd.to_timedelta, td_strings))
# Timedelta('-1 days +10:01:34.505418')
td_sum.total_seconds()
# -50305.494582
You can subtract date time like here to find how far apart these two times are:
https://stackoverflow.com/a/1345852/2415706
Adding two dates doesn't really make any sense though. Like, if you try to add Jan 1st of 2020 to Jan 1st of 1995, what are you expecting?
You can use datatime.timedelta class for this purpose.
You can find the documentation here.
You will need to parse your string and build a timedelta object.

Python, Getting stock data on particular days

I'm looking into getting data from the American stock exchanges for some python code, Basically what I need to do is import a stock name and previous date in time and it will give me all the data for the next 10 days of the market being open, Is this possible?
market = input("Market:")
ticker = input("Ticker:")
ticker = ticker.upper()
ystartdate = (input("Start Date IN FORMAT yyyy-mm-dd:"))
day1=input("Day1 :")
day2=input("Day2 :")
day3=input("Day3 :")
day4=input("Day4 :")
day5=input("Day5 :")
day6=input("Day6 :")
day7=input("Day7 :")
day8=input("Day8 :")
day9=input("Day9 :")
day10=input("Day10:")
Currently i have to input all the data automatically but that is a pain to do, Basically i would put in a stock and date like 2012-10-15 and it would go look at the stock on that date and for the next 10 days. If its possible it would be a life saver! Thanks
You should be working with a proper time format, not strings for this.
You can use pandas for example with datetime64.
import pandas as pd
input = ("Starting Date: ")
dates = pd.date_range(start=start_date, periods=10)
There is also the datetime package which has timedelta concepts which may help you if you don't want to use pandas.
I think what your need is included in pandas. In fact, you want to use either pandas.bdate_range or pandas.date_range with the freq argument set to B (I think both are more or less the same). These create business days, that is they would non include weekends. bdate_range also allows you to specify holidays, so I think that it might be a little more flexible.
>>> import pandas as pd
>>> dates = pd.bdate_range(start='2018-10-25', periods=10) # Start date is a Thursday
>>> print(dates)
DatetimeIndex(['2018-10-25', '2018-10-26', '2018-10-29', '2018-10-30',
'2018-10-31', '2018-11-01', '2018-11-02', '2018-11-05',
'2018-11-06', '2018-11-07'],
dtype='datetime64[ns]', freq='B')
Note how this excludes the 27th (a Saturday) and the 28th (a Sunday). If you want to specify holidays, you need to specify freq='C'.
Having these dates in separate variables is kind of ugly, but if you really want to, you can then go and unpack them like this:
>>> day1, day2, day3, day4, day5, day6, day7, day8, day9, day10 = dates

Python Date issue when starting a new month

I have an issue with a python request. In this request I need to set two dates, today and yesterday. This has functioned without issue throughout my testing until today.
The issue here being that of course we have just started a new month.
I am currently using the following date codes, however as i have now realized they do not take the monthly reset into consideration.
yesterday = str(datetime.datetime.today().month) + "/" +
str(datetime.datetime.today().day-1) + "/" +
str(datetime.datetime.today().year)
today = str(datetime.datetime.today().month) + "/" +
str(datetime.datetime.today().day) + "/" +
str(datetime.datetime.today().year)
As soon as the date is not 0 the application works like a charm.
Use datetime.timedelta
Ex:
import datetime
today = datetime.datetime.now()
print(today.strftime("%m/%d/%Y"))
yesterday = (today - datetime.timedelta(days=1)).strftime("%m/%d/%Y")
print(yesterday)
Output:
10/01/2018
09/30/2018
Use strftime to get your required date format in string
You make things too complicated, instead of worrying about "wrap arounds", etc. In your code you subtract the number of days with 1, but if we are the first of the month (for example October, 1st), then by subtracting one from it, we get "October 0th" (sic.).
You better perform the arithmetic on the date object:
yesterday_date = datetime.date.today() - datetime.timestamp(days=1)
and then convert it to a string with:
yesterday = yesterday_date.strftime('%m/%d/%Y')
At the moment of writing, this generates:
>>> yesterday_date.strftime('%m/%d/%Y')
'09/30/2018'
Performing arithmetic in the printing is giving "two responsibilities at once", and this is typically bad software design: the idea is one responsibility.

What is an efficient way to trim a date in Python?

Currently I am trying to trim the current date into day, month and year with the following code.
#Code from my local machine
from datetime import datetime
from datetime import timedelta
five_days_ago = datetime.now()-timedelta(days=5)
# result: 2017-07-14 19:52:15.847476
get_date = str(five_days_ago).rpartition(' ')[0]
#result: 2017-07-14
#Extract the day
day = get_date.rpartition('-')[2]
# result: 14
#Extract the year
year = get_date.rpartition('-')[0])
# result: 2017-07
I am not a Python professional because I grasp this language for a couple of months ago but I want to understand a few things here:
Why did I receive this 2017-07 if str.rpartition() is supposed to separate a string once you have declared some sort separator (-, /, " ")? I was expecting to receive 2017...
Is there an efficient way to separate day, month and year? I do not want to repeat the same mistakes with my insecure code.
I tried my code in the following tech. setups:
local machine with Python 3.5.2 (x64), Python 3.6.1 (x64) and repl.it with Python 3.6.1
Try the code online, copy and paste the line codes
Try the following:
from datetime import date, timedelta
five_days_ago = date.today() - timedelta(days=5)
day = five_days_ago.day
year = five_days_ago.year
If what you want is a date (not a date and time), use date instead of datetime. Then, the day and year are simply properties on the date object.
As to your question regarding rpartition, it works by splitting on the rightmost separator (in your case, the hyphen between the month and the day) - that's what the r in rpartition means. So get_date.rpartition('-') returns ['2017-07', '-', '14'].
If you want to persist with your approach, your year code would be made to work if you replace rpartition with partition, e.g.:
year = get_date.partition('-')[0]
# result: 2017
However, there's also a related (better) approach - use split:
parts = get_date.split('-')
year = parts[0]
month = parts[1]
day = parts[2]

Django/Python - Check a date is in current week

I would like to do something like this:
entries = Entry.objects.filter(created_at__in = current_week())
How to make it for good performance. Thanks!
Edit: I still have no idea for current_week() function.
Use __range. You'll need to actually calculate the beginning and end of the week first:
import datetime
date = datetime.date.today()
start_week = date - datetime.timedelta(date.weekday())
end_week = start_week + datetime.timedelta(7)
entries = Entry.objects.filter(created_at__range=[start_week, end_week])
Since Django 1.11, we you can use week Field lookup:
Entry.objects.filter(created_at__week=current_week)
It will give you the week from monday to sunday, according to ISO-8601.
To query for the current week:
from datetime import date
current_week = date.today().isocalendar()[1]
isocalendar() will return a tuple with 3 items: (ISO year, ISO week number, ISO weekday).
Yep, this question is at 2 years ago. Today with more experiences, I recommend using arrow with less pain in handling date time.
Checkout: https://github.com/crsmithdev/arrow

Categories

Resources