Python: get datetime for '3 years ago today' - python

In Python, how do I get a datetime object for '3 years ago today'?
UPDATE: FWIW, I don't care hugely about accuracy... i.e. it's Feb 29th today, I don't care whether I'm given Feb 28th or March 1st in my answer. Concision is more important than configurability, in this case.

If you need to be exact use the dateutil module to calculate relative dates
from datetime import datetime
from dateutil.relativedelta import relativedelta
three_yrs_ago = datetime.now() - relativedelta(years=3)

import datetime
datetime.datetime.now() - datetime.timedelta(days=3*365)

Subtracting 365*3 days is wrong, of course--you're crossing a leap year more than half the time.
dt = datetime.now()
dt = dt.replace(year=dt.year-3)
# datetime.datetime(2008, 3, 1, 13, 2, 36, 274276)
ED: To get the leap-year issue right,
def subtract_years(dt, years):
try:
dt = dt.replace(year=dt.year-years)
except ValueError:
dt = dt.replace(year=dt.year-years, day=dt.day-1)
return dt

def add_years(dt, years):
try:
result = datetime.datetime(dt.year + years, dt.month, dt.day, dt.hour, dt.minute, dt.second, dt.microsecond, dt.tzinfo)
except ValueError:
result = datetime.datetime(dt.year + years, dt.month, dt.day - 1, dt.hour, dt.minute, dt.second, dt.microsecond, dt.tzinfo)
return result
>>> add_years(datetime.datetime.now(), -3)
datetime.datetime(2008, 3, 1, 12, 2, 35, 22000)
>>> add_years(datetime.datetime(2008, 2, 29), -3)
datetime.datetime(2005, 2, 28, 0, 0)

This works to cater for leap year corner cases and non-leap years too. Because, if day = 29 and month = 2 (Feb), a non-leap year would throw a value error because there is no 29th Feb and the last day of Feb would be 28th, thus doing a -1 on the date works in a try-except block.
from datetime import datetime
last_year = datetime.today().year - 1
month = datetime.today().month
day = datetime.today().day
try:
# try returning same date last year
last_year_date = datetime.strptime(f"{last_year}-{month}-{day}",'%Y-%m-%d').date()
except ValueError:
# incase of error due to leap year, return date - 1 in last year
last_year_date = datetime.strptime(f"{last_year}-{month}-{day-1}",'%Y-%m-%d').date()
print(last_year_date)

In [3]: import datetime as dt
In [4]: today=dt.date.today()
In [5]: three_years_ago=today-dt.timedelta(days=3*365)
In [6]: three_years_ago
Out[6]: datetime.date(2008, 3, 1)

I was looking for a solution using only the standard library, and this worked for me. Note that without the check, Feb. 29th will give you a ValueError for most years. On all other days, it will give you the date for "three years ago today".
today = date.today()
day = 28 if today.month == 2 and today.day == 29 else today.day
three_years_ago = date(today.year - 3, today.month, day)

Why not simply do a check for leap year before replacing the year.
This does not need any extra package or try:Except.
def years_ago(dt, years):
if dt.month == 2 and dt.day == 29:
dt = dt.replace(day=28)
return dt.replace(year=dt.year - years)

Related

Getting the business day number using a date and holiday calendar in python [duplicate]

I need to subtract business days from the current date.
I currently have some code which needs always to be running on the most recent business day. So that may be today if we're Monday thru Friday, but if it's Saturday or Sunday then I need to set it back to the Friday before the weekend. I currently have some pretty clunky code to do this:
lastBusDay = datetime.datetime.today()
if datetime.date.weekday(lastBusDay) == 5: #if it's Saturday
lastBusDay = lastBusDay - datetime.timedelta(days = 1) #then make it Friday
elif datetime.date.weekday(lastBusDay) == 6: #if it's Sunday
lastBusDay = lastBusDay - datetime.timedelta(days = 2); #then make it Friday
Is there a better way?
Can I tell timedelta to work in weekdays rather than calendar days for example?
Use pandas!
import datetime
# BDay is business day, not birthday...
from pandas.tseries.offsets import BDay
today = datetime.datetime.today()
print(today - BDay(4))
Since today is Thursday, Sept 26, that will give you an output of:
datetime.datetime(2013, 9, 20, 14, 8, 4, 89761)
If you want to skip US holidays as well as weekends, this worked for me (using pandas 0.23.3):
import pandas as pd
from pandas.tseries.holiday import USFederalHolidayCalendar
from pandas.tseries.offsets import CustomBusinessDay
US_BUSINESS_DAY = CustomBusinessDay(calendar=USFederalHolidayCalendar())
july_5 = pd.datetime(2018, 7, 5)
result = july_5 - 2 * US_BUSINESS_DAY # 2018-7-2
To convert to a python date object I did this:
result.to_pydatetime().date()
Maybe this code could help:
lastBusDay = datetime.datetime.today()
shift = datetime.timedelta(max(1,(lastBusDay.weekday() + 6) % 7 - 3))
lastBusDay = lastBusDay - shift
The idea is that on Mondays yo have to go back 3 days, on Sundays 2, and 1 in any other day.
The statement (lastBusDay.weekday() + 6) % 7 just re-bases the Monday from 0 to 6.
Really don't know if this will be better in terms of performance.
There seem to be several options if you're open to installing extra libraries.
This post describes a way of defining workdays with dateutil.
http://coding.derkeiler.com/Archive/Python/comp.lang.python/2004-09/3758.html
BusinessHours lets you custom-define your list of holidays, etc., to define when your working hours (and by extension working days) are.
http://pypi.python.org/pypi/BusinessHours/
DISCLAMER: I'm the author...
I wrote a package that does exactly this, business dates calculations. You can use custom week specification and holidays.
I had this exact problem while working with financial data and didn't find any of the available solutions particularly easy, so I wrote one.
Hope this is useful for other people.
https://pypi.python.org/pypi/business_calendar/
If somebody is looking for solution respecting holidays (without any huge library like pandas), try this function:
import holidays
import datetime
def previous_working_day(check_day_, holidays=holidays.US()):
offset = max(1, (check_day_.weekday() + 6) % 7 - 3)
most_recent = check_day_ - datetime.timedelta(offset)
if most_recent not in holidays:
return most_recent
else:
return previous_working_day(most_recent, holidays)
check_day = datetime.date(2020, 12, 28)
previous_working_day(check_day)
which produces:
datetime.date(2020, 12, 24)
timeboard package does this.
Suppose your date is 04 Sep 2017. In spite of being a Monday, it was a holiday in the US (the Labor Day). So, the most recent business day was Friday, Sep 1.
>>> import timeboard.calendars.US as US
>>> clnd = US.Weekly8x5()
>>> clnd('04 Sep 2017').rollback().to_timestamp().date()
datetime.date(2017, 9, 1)
In UK, 04 Sep 2017 was the regular business day, so the most recent business day was itself.
>>> import timeboard.calendars.UK as UK
>>> clnd = UK.Weekly8x5()
>>> clnd('04 Sep 2017').rollback().to_timestamp().date()
datetime.date(2017, 9, 4)
DISCLAIMER: I am the author of timeboard.
For the pandas usecase, I found the following to be quite useful and compact, although not completely readable:
Get most recent previous business day:
In [2]: datetime.datetime(2019, 11, 30) + BDay(1) - BDay(1) # Saturday
Out[2]: Timestamp('2019-11-29 00:00:00')
In [3]: datetime.datetime(2019, 11, 29) + BDay(1) - BDay(1) # Friday
Out[3]: Timestamp('2019-11-29 00:00:00')
In the other direction, simply use:
In [4]: datetime.datetime(2019, 11, 30) + BDay(0) # Saturday
Out[4]: Timestamp('2019-12-02 00:00:00')
In [5]: datetime.datetime(2019, 11, 29) + BDay(0) # Friday
Out[5]: Timestamp('2019-11-29 00:00:00')
This will give a generator of working days, of course without holidays, stop is datetime.datetime object. If you need holidays just make additional argument with list of holidays and check with 'IFology' ;-)
def workingdays(stop, start=datetime.date.today()):
while start != stop:
if start.weekday() < 5:
yield start
start += datetime.timedelta(1)
Later on you can count them like
workdays = workingdays(datetime.datetime(2015, 8, 8))
len(list(workdays))
def getNthBusinessDay(startDate, businessDaysInBetween):
currentDate = startDate
daysToAdd = businessDaysInBetween
while daysToAdd > 0:
currentDate += relativedelta(days=1)
day = currentDate.weekday()
if day < 5:
daysToAdd -= 1
return currentDate
When I am writing this answer, today is Friday in USA so next business day shall be Monday, in the meantime yesterday is thanksgiving holiday so previous business day should be Wednesday
So today date of Friday, November 24, 2022, is a perfect time to get the previous, current and next business days.
By having trial and error, I could only find the correct output by combining the method as below:
from datetime import datetime, timedelta
from pandas.tseries.offsets import BDay
from pandas.tseries.offsets import CustomBusinessDay
from pandas.tseries.holiday import USFederalHolidayCalendar
US_BUSINESS_DAY = CustomBusinessDay(calendar=USFederalHolidayCalendar())
TODAY = datetime.today() - 1 * US_BUSINESS_DAY
YESTERDAY = (datetime.today() - timedelta(max(1,(TODAY.weekday() + 6) % 7 - 3))) - 1 * US_BUSINESS_DAY
TOMORROW = TODAY + BDay(1)
DAY_NAME = ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday','Sunday']
BUSINESS_DATE = "[Previous (" + DAY_NAME[YESTERDAY.weekday()] + "):'" + YESTERDAY.strftime('%y%m%d')
BUSINESS_DATE += "', Current (" + DAY_NAME[TODAY.weekday()] + "):'" + TODAY.strftime('%y%m%d')
BUSINESS_DATE += "', Next (" + DAY_NAME[TOMORROW.weekday()] + "):'" + TOMORROW.strftime('%y%m%d') + "']"
print_("Business Date USA = ", BUSINESS_DATE)
Output:
Business Date USA = [Previous (Wednesday):'221123', Current (Friday):'221125', Next (Monday):'221128']
Getting the most recent business day:
pd.bdate_range(end=(pd.to_datetime('today').date()), periods=1)[0])
OR in case you want it as a 'datetime.date' type:
(pd.bdate_range(end=(pd.to_datetime('today').date()), periods=1)[0]).date()
The accepted answer actually gives an incorrect result because today - BDay(0) rounds forward to Monday during the weekend instead of back to Friday like the question states. What you'd want is BusinessDay().rollback() which rolls back to the prior business day (the accepted answer matches BusinessDay().rollforward() logic).
import pandas as pd
import datetime
today = datetime.datetime.today()
prior_bday = pd.tseries.offsets.BusinessDay().rollback(today)
Why don't you try something like:
lastBusDay = datetime.datetime.today()
if datetime.date.weekday(lastBusDay) not in range(0,5):
lastBusDay = 5
another simplify version
lastBusDay = datetime.datetime.today()
wk_day = datetime.date.weekday(lastBusDay)
if wk_day > 4: #if it's Saturday or Sunday
lastBusDay = lastBusDay - datetime.timedelta(days = wk_day-4) #then make it Friday
Solution irrespective of different jurisdictions having different holidays:
If you need to find the right id within a table, you can use this snippet. The Table model is a sqlalchemy model and the dates to search from are in the field day.
def last_relevant_date(db: Session, given_date: date) -> int:
available_days = (db.query(Table.id, Table.day)
.order_by(desc(Table.day))
.limit(100).all())
close_dates = pd.DataFrame(available_days)
close_dates['delta'] = close_dates['day'] - given_date
past_dates = (close_dates
.loc[close_dates['delta'] < pd.Timedelta(0, unit='d')])
table_id = int(past_dates.loc[past_dates['delta'].idxmax()]['id'])
return table_id
This is not a solution that I would recommend when you have to convert in bulk. It is rather generic and expensive as you are not using joins. Moreover, it assumes that you have a relevant day that is one of the 100 most recent days in the model Table. So it tackles data input that may have different dates.
Get first day of month, last day of month and last business day of previous month if last day falls on weekend Saturday/Sunday
from datetime import datetime, timedelta
from dateutil.relativedelta import relativedelta
day = datetime(2023, 1, 10)
#last day of (n) previous month (n=months)
#n = 0 -- for current month
n=1
lastDayMonth = ((day - relativedelta(months=n) + relativedelta(day=31)).date());
#First day of previous month (n=months=1)
firstDayMonth = ((day - relativedelta(months=n) + relativedelta(day=1)).date());
print("Last Day of Month - "+ str(lastDayMonth))
print("First Day of Month - "+ str(firstDayMonth))
#Last business day (Friday) of prev (n) month (n=months=1)
lastBusDay = (lastDayMonth - timedelta(max(1,(lastDayMonth.weekday() + 6) % 7 - 3))) if lastDayMonth.weekday() in (5,6) else lastDayMonth
print("Last Business Day of Month - " + str(lastBusDay))
print()
--- Output
Last Day of Month - 2022-12-31
First Day of Month - 2022-12-01
Last Business Day of Month - 2022-12-30

Converting week numbers to dates

Say I have a week number of a given year (e.g. week number 6 of 2014).
How can I convert this to the date of the Monday that starts that week?
One brute force solution I thought of would be to go through all Mondays of the year:
date1 = datetime.date(1,1,2014)
date2 = datetime.date(12,31,2014)
def monday_range(date1,date2):
while date1 < date2:
if date1.weekday() == 0:
yield date1
date1 = date1 + timedelta(days=1)
and store a hash from the first to the last Monday of the year, but this wouldn't do it, since, the first week of the year may not contain a Monday.
You could just feed the data into time.asctime().
>>> import time
>>> week = 6
>>> year = 2014
>>> atime = time.asctime(time.strptime('{} {} 1'.format(year, week), '%Y %W %w'))
>>> atime
'Mon Feb 10 00:00:00 2014'
EDIT:
To convert this to a datetime.date object:
>>> datetime.datetime.fromtimestamp(time.mktime(atime)).date()
datetime.date(2014, 2, 10)
All about strptime \ strftime:
https://docs.python.org/2/library/datetime.html
mytime.strftime('%U') #for W\C Monday
mytime.strftime('%W') #for W\C Sunday
Sorry wrong way around
from datetime import datetime
mytime=datetime.strptime('2012W6 MON'. '%YW%U %a')
Strptime needs to see both the year and the weekday to do this. I'm assuming you've got weekly data so just add 'mon' to the end of the string.
Enjoy
A simple function to get the Monday, given a date.
def get_monday(dte):
return dte - datetime.timedelta(days = dte.weekday())
Some sample output:
>>> get_monday(date1)
datetime.date(2013, 12, 30)
>>> get_monday(date2)
datetime.date(2014, 12, 29)
Call this function within your loop.
We can just add the number of weeks to the first day of the year.
>>> import datetime
>>> from dateutil.relativedelta import relativedelta
>>> week = 40
>>> year = 2019
>>> date = datetime.date(year,1,1)+relativedelta(weeks=+week)
>>> date
datetime.date(2019, 10, 8)
To piggyback and give a different version of the answer #anon582847382 gave, you can do something like the below code if you're creating a function for it and the week number is given like "11-2023":
import time
from datetime import datetime
def get_date_from_week_number(str_value):
temp_str = time.asctime(time.strptime('{} {} 1'.format(str_value[3:7], str_value[0:2]), '%Y %W %w'))
return datetime.strptime(temp_str, '%a %b %d %H:%M:%S %Y').date()

How do I find the nth day of the next month in Python?

I am trying to get the date delta by subtracting today's date from the nth day of the next month.
delta = nth_of_next_month - todays_date
print delta.days
How do you get the date object for the 1st (or 2nd, 3rd.. nth) day of the next month. I tried taking the month number from the date object and increasing it by 1. Which is obviously a dumb idea because 12 + 1 = 13. I also tried adding one month to today and tried to get to the first of the month. I am sure that there is a much more efficient way of doing this.
The dateutil library is useful for this:
from dateutil.relativedelta import relativedelta
from datetime import datetime
# Where day is the day you want in the following month
dt = datetime.now() + relativedelta(months=1, day=20)
This should be straightforward unless I'm missing something in your question:
import datetime
now = datetime.datetime.now()
nth_day = 5
next_month = now.month + 1 if now.month < 12 else 1 # February
year = now.year if now.month < 12 else now.year+1
nth_of_next_month = datetime.datetime(year, next_month, nth_day)
print(nth_of_next_month)
Result:
2014-02-05 00:00:00
Using dateutil as suggested in another answer is a much better idea than this, though.
Another alternative is to use delorean library:
Delorean is a library that provides easy and convenient datetime
conversions in Python.
>>> from delorean import Delorean
>>> d = Delorean()
>>> d.next_month()
Delorean(datetime=2014-02-15 18:51:14.325350+00:00, timezone=UTC)
>>> d.next_month().next_day(2)
Delorean(datetime=2014-02-17 18:51:14.325350+00:00, timezone=UTC)
My approach to calculating the next month without external libraries:
def nth_day_of_next_month(dt, n):
return dt.replace(
year=dt.year + (dt.month // 12), # +1 for december, +0 otherwise
month=(dt.month % 12) + 1, # december becomes january
day=n)
This works for both datetime.datetime() and datetime.date() objects.
Demo:
>>> import datetime
>>> def nth_day_of_next_month(dt, n):
... return dt.replace(year=dt.year + (dt.month // 12), month=(dt.month % 12) + 1, day=n)
...
>>> nth_day_of_next_month(datetime.datetime.now(), 4)
datetime.datetime(2014, 2, 4, 19, 20, 51, 177860)
>>> nth_day_of_next_month(datetime.date.today(), 18)
datetime.date(2014, 2, 18)
Without using any external library, this can be achived as follows
from datetime import datetime, timedelta
def nth_day_of_next_month(n):
today = datetime.now()
next_month_dt = today + timedelta(days=32-today.day)
return next_month_dt.replace(day=n)

Datetime expiration next year

I have a UTCDateTime object in python and I need to check if it is after today but within the next year. What is the best way to achieve this?
Thanks in advance
Changed from 13 months to 1 year.
now = datetime.datetime.utcnow()
if now.month < 12:
expire_date = now.replace(year=now.year + 1, month=now.month + 1)
else:
expire_date = now.replace(year=now.year + 2, month=0)
although... this will still fail if you run it on, say, January 31st since February 31st doesn't exist. There are a few conditions you can add related to month dependencies to avoid these problems.
If you changed it to 12 months (re: comment), you only have to worry about leap years.
now = datetime.datetime.utcnow()
exp_year = now.year + 1
exp_month = now.month
exp_day = now.day
if exp_month == 2 and exp_day == 29:
exp_month += 1
exp_day = 1
exp_date = now.replace(year=exp_year, month=exp_month, day=exp_day)
The dateutil module can handle this for you... (Works same with datetime's as well)
from datetime import date
from dateutil import relativedelta
from date import date
d = date(2011, 1, 31)
delta = relativedelta.relativedelta(months=13)
d + delta
#datetime.date(2011, 2, 28)

Most recent previous business day in Python

I need to subtract business days from the current date.
I currently have some code which needs always to be running on the most recent business day. So that may be today if we're Monday thru Friday, but if it's Saturday or Sunday then I need to set it back to the Friday before the weekend. I currently have some pretty clunky code to do this:
lastBusDay = datetime.datetime.today()
if datetime.date.weekday(lastBusDay) == 5: #if it's Saturday
lastBusDay = lastBusDay - datetime.timedelta(days = 1) #then make it Friday
elif datetime.date.weekday(lastBusDay) == 6: #if it's Sunday
lastBusDay = lastBusDay - datetime.timedelta(days = 2); #then make it Friday
Is there a better way?
Can I tell timedelta to work in weekdays rather than calendar days for example?
Use pandas!
import datetime
# BDay is business day, not birthday...
from pandas.tseries.offsets import BDay
today = datetime.datetime.today()
print(today - BDay(4))
Since today is Thursday, Sept 26, that will give you an output of:
datetime.datetime(2013, 9, 20, 14, 8, 4, 89761)
If you want to skip US holidays as well as weekends, this worked for me (using pandas 0.23.3):
import pandas as pd
from pandas.tseries.holiday import USFederalHolidayCalendar
from pandas.tseries.offsets import CustomBusinessDay
US_BUSINESS_DAY = CustomBusinessDay(calendar=USFederalHolidayCalendar())
july_5 = pd.datetime(2018, 7, 5)
result = july_5 - 2 * US_BUSINESS_DAY # 2018-7-2
To convert to a python date object I did this:
result.to_pydatetime().date()
Maybe this code could help:
lastBusDay = datetime.datetime.today()
shift = datetime.timedelta(max(1,(lastBusDay.weekday() + 6) % 7 - 3))
lastBusDay = lastBusDay - shift
The idea is that on Mondays yo have to go back 3 days, on Sundays 2, and 1 in any other day.
The statement (lastBusDay.weekday() + 6) % 7 just re-bases the Monday from 0 to 6.
Really don't know if this will be better in terms of performance.
There seem to be several options if you're open to installing extra libraries.
This post describes a way of defining workdays with dateutil.
http://coding.derkeiler.com/Archive/Python/comp.lang.python/2004-09/3758.html
BusinessHours lets you custom-define your list of holidays, etc., to define when your working hours (and by extension working days) are.
http://pypi.python.org/pypi/BusinessHours/
DISCLAMER: I'm the author...
I wrote a package that does exactly this, business dates calculations. You can use custom week specification and holidays.
I had this exact problem while working with financial data and didn't find any of the available solutions particularly easy, so I wrote one.
Hope this is useful for other people.
https://pypi.python.org/pypi/business_calendar/
If somebody is looking for solution respecting holidays (without any huge library like pandas), try this function:
import holidays
import datetime
def previous_working_day(check_day_, holidays=holidays.US()):
offset = max(1, (check_day_.weekday() + 6) % 7 - 3)
most_recent = check_day_ - datetime.timedelta(offset)
if most_recent not in holidays:
return most_recent
else:
return previous_working_day(most_recent, holidays)
check_day = datetime.date(2020, 12, 28)
previous_working_day(check_day)
which produces:
datetime.date(2020, 12, 24)
timeboard package does this.
Suppose your date is 04 Sep 2017. In spite of being a Monday, it was a holiday in the US (the Labor Day). So, the most recent business day was Friday, Sep 1.
>>> import timeboard.calendars.US as US
>>> clnd = US.Weekly8x5()
>>> clnd('04 Sep 2017').rollback().to_timestamp().date()
datetime.date(2017, 9, 1)
In UK, 04 Sep 2017 was the regular business day, so the most recent business day was itself.
>>> import timeboard.calendars.UK as UK
>>> clnd = UK.Weekly8x5()
>>> clnd('04 Sep 2017').rollback().to_timestamp().date()
datetime.date(2017, 9, 4)
DISCLAIMER: I am the author of timeboard.
For the pandas usecase, I found the following to be quite useful and compact, although not completely readable:
Get most recent previous business day:
In [2]: datetime.datetime(2019, 11, 30) + BDay(1) - BDay(1) # Saturday
Out[2]: Timestamp('2019-11-29 00:00:00')
In [3]: datetime.datetime(2019, 11, 29) + BDay(1) - BDay(1) # Friday
Out[3]: Timestamp('2019-11-29 00:00:00')
In the other direction, simply use:
In [4]: datetime.datetime(2019, 11, 30) + BDay(0) # Saturday
Out[4]: Timestamp('2019-12-02 00:00:00')
In [5]: datetime.datetime(2019, 11, 29) + BDay(0) # Friday
Out[5]: Timestamp('2019-11-29 00:00:00')
This will give a generator of working days, of course without holidays, stop is datetime.datetime object. If you need holidays just make additional argument with list of holidays and check with 'IFology' ;-)
def workingdays(stop, start=datetime.date.today()):
while start != stop:
if start.weekday() < 5:
yield start
start += datetime.timedelta(1)
Later on you can count them like
workdays = workingdays(datetime.datetime(2015, 8, 8))
len(list(workdays))
def getNthBusinessDay(startDate, businessDaysInBetween):
currentDate = startDate
daysToAdd = businessDaysInBetween
while daysToAdd > 0:
currentDate += relativedelta(days=1)
day = currentDate.weekday()
if day < 5:
daysToAdd -= 1
return currentDate
When I am writing this answer, today is Friday in USA so next business day shall be Monday, in the meantime yesterday is thanksgiving holiday so previous business day should be Wednesday
So today date of Friday, November 24, 2022, is a perfect time to get the previous, current and next business days.
By having trial and error, I could only find the correct output by combining the method as below:
from datetime import datetime, timedelta
from pandas.tseries.offsets import BDay
from pandas.tseries.offsets import CustomBusinessDay
from pandas.tseries.holiday import USFederalHolidayCalendar
US_BUSINESS_DAY = CustomBusinessDay(calendar=USFederalHolidayCalendar())
TODAY = datetime.today() - 1 * US_BUSINESS_DAY
YESTERDAY = (datetime.today() - timedelta(max(1,(TODAY.weekday() + 6) % 7 - 3))) - 1 * US_BUSINESS_DAY
TOMORROW = TODAY + BDay(1)
DAY_NAME = ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday','Sunday']
BUSINESS_DATE = "[Previous (" + DAY_NAME[YESTERDAY.weekday()] + "):'" + YESTERDAY.strftime('%y%m%d')
BUSINESS_DATE += "', Current (" + DAY_NAME[TODAY.weekday()] + "):'" + TODAY.strftime('%y%m%d')
BUSINESS_DATE += "', Next (" + DAY_NAME[TOMORROW.weekday()] + "):'" + TOMORROW.strftime('%y%m%d') + "']"
print_("Business Date USA = ", BUSINESS_DATE)
Output:
Business Date USA = [Previous (Wednesday):'221123', Current (Friday):'221125', Next (Monday):'221128']
Getting the most recent business day:
pd.bdate_range(end=(pd.to_datetime('today').date()), periods=1)[0])
OR in case you want it as a 'datetime.date' type:
(pd.bdate_range(end=(pd.to_datetime('today').date()), periods=1)[0]).date()
The accepted answer actually gives an incorrect result because today - BDay(0) rounds forward to Monday during the weekend instead of back to Friday like the question states. What you'd want is BusinessDay().rollback() which rolls back to the prior business day (the accepted answer matches BusinessDay().rollforward() logic).
import pandas as pd
import datetime
today = datetime.datetime.today()
prior_bday = pd.tseries.offsets.BusinessDay().rollback(today)
Why don't you try something like:
lastBusDay = datetime.datetime.today()
if datetime.date.weekday(lastBusDay) not in range(0,5):
lastBusDay = 5
another simplify version
lastBusDay = datetime.datetime.today()
wk_day = datetime.date.weekday(lastBusDay)
if wk_day > 4: #if it's Saturday or Sunday
lastBusDay = lastBusDay - datetime.timedelta(days = wk_day-4) #then make it Friday
Solution irrespective of different jurisdictions having different holidays:
If you need to find the right id within a table, you can use this snippet. The Table model is a sqlalchemy model and the dates to search from are in the field day.
def last_relevant_date(db: Session, given_date: date) -> int:
available_days = (db.query(Table.id, Table.day)
.order_by(desc(Table.day))
.limit(100).all())
close_dates = pd.DataFrame(available_days)
close_dates['delta'] = close_dates['day'] - given_date
past_dates = (close_dates
.loc[close_dates['delta'] < pd.Timedelta(0, unit='d')])
table_id = int(past_dates.loc[past_dates['delta'].idxmax()]['id'])
return table_id
This is not a solution that I would recommend when you have to convert in bulk. It is rather generic and expensive as you are not using joins. Moreover, it assumes that you have a relevant day that is one of the 100 most recent days in the model Table. So it tackles data input that may have different dates.
Get first day of month, last day of month and last business day of previous month if last day falls on weekend Saturday/Sunday
from datetime import datetime, timedelta
from dateutil.relativedelta import relativedelta
day = datetime(2023, 1, 10)
#last day of (n) previous month (n=months)
#n = 0 -- for current month
n=1
lastDayMonth = ((day - relativedelta(months=n) + relativedelta(day=31)).date());
#First day of previous month (n=months=1)
firstDayMonth = ((day - relativedelta(months=n) + relativedelta(day=1)).date());
print("Last Day of Month - "+ str(lastDayMonth))
print("First Day of Month - "+ str(firstDayMonth))
#Last business day (Friday) of prev (n) month (n=months=1)
lastBusDay = (lastDayMonth - timedelta(max(1,(lastDayMonth.weekday() + 6) % 7 - 3))) if lastDayMonth.weekday() in (5,6) else lastDayMonth
print("Last Business Day of Month - " + str(lastBusDay))
print()
--- Output
Last Day of Month - 2022-12-31
First Day of Month - 2022-12-01
Last Business Day of Month - 2022-12-30

Categories