Get fiscal year based on current timestamp-python - python

I am trying get the start date of the financial year based on today's date.
So after a little research, I found this package called fiscalyear where you can modify the start date of the fiscal year. In my case i wanted 01-07-year to be the start date of my fiscal year so i set fiscalyear.START_MONTH = 7
I have tried the below(reproducible example if you pip install fiscalyear):
import datetime
import fiscalyear
fiscalyear.START_MONTH = 7
a = fiscalyear.FiscalYear(datetime.datetime.now().year).start.date()
a.strftime('%Y-%m-%d')
Which outputs correctly:
'2018-07-01'
However, this would not work when the month turns to August, since the datetime.datetime.now().year doesnot change. So i tried doing something like:
if (datetime.datetime.now()-pd.to_datetime('2018-07-01')).days < 365:
a = fiscalyear.FiscalYear(datetime.datetime.now().year).start.date()
print(a.strftime('%Y-%m-%d'))
else:
a = fiscalyear.FiscalYear(datetime.datetime.now().year+1).start.date()
print(a.strftime('%Y-%m-%d'))
I have a bad feeling about what I am doing since this might now work for leap years too.
Is there some better way to do this in python which will detect the start date of the fiscal year based on current timestamp?
py version: 3.6.7

My knowledge in the fiscal area is somewhere close to Zero, but according to [ReadTheDocs.FiscalYear]: Basic Usage:
The FiscalYear class provides an object for storing information about the start and end of a particular fiscal year.
...
The start and end of each of the above objects are stored as instances of the FiscalDateTime class. This class provides all of the same features as the datetime class, with the addition of the ability to query the fiscal year, fiscal quarter, fiscal month, and fiscal day.
So, FiscalYear isn't to be used with dates, but FiscalDateTime (or its simpler sibling: FiscalDate) instead.
>>> import fiscalyear
>>> fiscalyear.START_MONTH = 7
>>>
>>> cur_y = fiscalyear.FiscalYear(datetime.datetime.now().year)
>>> cur_y.start.date()
datetime.date(2018, 7, 1)
>>> cur_y.end.date()
datetime.date(2019, 6, 30)
>>>
>>> cur_dt = fiscalyear.FiscalDate(2019, 2, 19) # Current date (at answer time)
>>> cur_dt.fiscal_year
2019
>>>
>>> jul_dt = fiscalyear.FiscalDate(2019, 7, 19) # A date past July 1st (when the fiscal year should change)
>>> jul_dt.fiscal_year
2020

You can try following code, It worked for me:
>>> import fiscalyear
>>> fiscalyear.START_MONTH = 4
>>> fiscalyear.FiscalYear.current()
FiscalYear(2021)
>>>

I think you need searchsorted with helper DatetimeIndex:
r = pd.to_datetime([f'{x}-06-30' for x in range(1970, 2021)])
#print (r)
for x in ['2017-07-01','2017-07-02','2018-06-30','2019-02-19','2019-08-19']:
out = (r[r.searchsorted(pd.Timestamp(x))] + pd.Timedelta(1, 'd')).year
print (out)
2018
2018
2018
2019
2020

Taking a sample dataframe:
pd.DataFrame(dict(
dates=[pd.datetime(2018, 6, 1), pd.datetime(2018, 7, 1), pd.datetime(2018, 7, 2)],
values=[0]*3
))
dates values
0 2018-06-01 0
1 2018-07-01 0
2 2018-07-02 0
... I have used pd.Grouper() to group these down to date starting July 1st, where the key is AS-JUL i.e. 'annual-starting July'
df.groupby(pd.Grouper(freq='AS-JUL', key='dates')).count()
values
values
dates
2017-07-01 1
2018-07-01 2
You can see here that 2018-07-01 remains as 2018-07-01 after the operation

Related

Python - Convert 5 digit date to datetime from SAS date

I have a 5 digit date variable that was exported from SAS. I am having trouble converting it into a datetime format in Python. The variable is currently stored as an object.
Here is a background on SAS dates:
"The SAS System represents dates as the number of days since a reference date. The reference date, or date zero, used for SAS date values is 1 January 1960. Thus, for example, 3 February 1960 is represented by the SAS System as 33. The SAS date for 17 October 1991 is 11612."
Here are two examples:
Let's try pd.to_datetime with specified origin and unit
df['out'] = pd.to_datetime(df['Date'], unit='D', origin='1960-01-01')
print(df)
Date out
0 21032 2017-08-01
1 16387 2004-11-12
2 0 1960-01-01
3 33 1960-02-03
4 11612 1991-10-17
#Ynjxsjmh 's answer is better than mine, however you could retrieve the date you're looking for by adding the deltatime between your 'origin' date and the input(integer of amount of days to add upon origin) :
import datetime
date = datetime.datetime(1960, 1, 1) # Constant for SAS date
def SASdate(days:int):
"""
Convert SAS integer to date
"""
return date + datetime.timedelta(days = days)
print(SASdate(0))

Pyspark : get next_day from a variable

I use deltatime to subtract 12 weeks and get the exact date
but from this date I have to recover on Friday. this means that if we subtract 12 weeks I have Monday January 3, I have to make a change to get Friday January 7.
Code exemple :
I use this code to get the initial date :
week_num_period = datetime.today()- timedelta(weeks=12)
week_start_perioddddd = week_num_period.strftime("%Y-%m-%d")
but from that date i need to get the friday of that week !
i tried with
week_start_period = next_day(week_start_perioddddd, 'Friday')
week_start_period
but next_day doesn't apply on str !
could someone help me ?
So you want to get the formatted date for the Friday from the week 12 weeks ago?
Add the timedelta of: 4 (weekday index of Friday) minus the weekday index of the day you calculated.
>>> week_num_period = datetime.today()- timedelta(weeks=12)
>>> week_num_period.date()
datetime.date(2022, 1, 6)
>>> friday = week_num_period + timedelta(days=4 - week_num_period.weekday())
>>> friday.date()
datetime.date(2022, 1, 7)
>>> week_start_period = friday.strftime("%Y-%m-%d")
>>> week_start_period
'2022-01-07'
>>>

How can I find the fiscal Week of date in Pandas

I have a column with many dates: sample of the said list below
Dates
1 2019-02-01
2 2018-03-10
3 2019-08-01
4 2020-02-07
I would like to have it so that if input a date, of any year I can get the week number.
However, the fiscal year starts on Aug 1 of any given year.
I tried just shifting the date to Jan 1 but it's different for every year due to leap years.
data['Dates'] = pd.to_datetime(data['Dates'])
data['Week'] = (data['Dates'] - timedelta(days=215)).week
print(data)
how can I get a result similar to this one below
Dates Week
1 2019-02-01 27
2 2018-03-10 32
3 2019-08-01 1
4 2020-02-07 28
-Note: the weeks are probably incorrect.
The other answer ignores the fiscal year part of the OP. I am leaving the fiscal year start date calc to the reader but this will calculate the week number (where Monday is the start of the week) from an arbitrary start date.
from dateutil import relativedelta
from datetime import date, datetime, timedelta
NEXT_MONDAY = relativedelta.relativedelta(weekday=relativedelta.MO)
LAST_MONDAY = relativedelta.relativedelta(weekday=relativedelta.MO(-1))
ONE_WEEK = timedelta(weeks=1)
def week_in_fiscal_year(d: date, fiscal_year_start: date) -> int:
fy_week_2_monday = fiscal_year_start + NEXT_MONDAY
if d < fy_week_2_monday:
return 1
else:
cur_week_monday = d + LAST_MONDAY
return int((cur_week_monday - fy_week_2_monday) / ONE_WEEK) + 2
adapted from this post
Convert it to a datetime, then call datetime.date(2010, 6, 16).strftime("%V")4
You can also use isocalendar which will return a tuple, as opposed to a string above datetime.date(2010, 6, 16).isocalendar()[1]
How to get week number in Python?

Get week start date from week number

This question is related to Get date from week number, and is possibly a duplicate of the latter, however, I think what is suggested in the accepted answer to that question does not really work.
In [6]: datetime.datetime.strptime('2019-18-1', "%Y-%W-%w")
Out[6]: datetime.datetime(2019, 5, 6, 0, 0)
Notice how it returns Monday 2019-5-6. However, according to the calendar (I use http://whatweekisit.org for reference), 2019-5-6 the Monday of week 19.
Similarly, the example provided in the original question:
In [7]: datetime.datetime.strptime('2013-26-1', "%Y-%W-%w")
Out[7]: datetime.datetime(2013, 7, 1, 0, 0)
According to http://whatweekisit.org/calendar-2013.html 2013-7-1 is the Monday of week 27.
Also
In [8]: datetime.datetime.strptime('2019-18-1', "%Y-%W-%w").isocalendar()[1]
Out[8]: 19
Notice how I give week 18 to strptime, and get week 19 back from isocalendar.
I am completely lost and would very much appreciate if someone could explain what is going on here. My original goal though is to get week start date from week number.
Based off of my testing, datetime does not consider the first week of 2019 (i.e. Jan 1-Jan 6) as week 1 because it isn't a full week; December 31st, 2018 is part of the week but is not in 2019. I suppose you'll have to accomodate for that by checking the output of datetime.datetime.strptime('year-1-1', "%Y-%W-%w") == datetime.datetime.strptime('year-0-1', "%Y-%W-%w"). If false, subtract 1.
2018 is an example of a year where datetime does return the same value as isocalendar because the first Monday of the year is Jan 1.
From the isocalendar docs:
The ISO year consists of 52 or 53 full weeks, and where a week starts on a Monday and ends on a Sunday. The first week of an ISO year is the first (Gregorian) calendar week of a year containing a Thursday. This is called week number 1, and the ISO year of that Thursday is the same as its Gregorian year.
On the other hand, strptime starts from the first full week, in fact, since 2019 starts from Tuesday, they start from different weeks:
import datetime as dt
strp_first = dt.datetime.strptime('2019-1-1', "%Y-%W-%w")
>>> print(strp_first)
2019-01-07 00:00:00
>>> print(strp_first.isocalendar()[1])
2
While in 2021, which starts from Friday:
strp_first = dt.datetime.strptime('2021-1-1', "%Y-%W-%w")
>>> print(strp_first)
2021-01-04 00:00:00
>>> print(strp_first.isocalendar()[1])
1

Find the date for the first Monday after a given date

Given a particular date, say 2011-07-02, how can I find the date of the next Monday (or any weekday day for that matter) after that date?
import datetime
def next_weekday(d, weekday):
days_ahead = weekday - d.weekday()
if days_ahead <= 0: # Target day already happened this week
days_ahead += 7
return d + datetime.timedelta(days_ahead)
d = datetime.date(2011, 7, 2)
next_monday = next_weekday(d, 0) # 0 = Monday, 1=Tuesday, 2=Wednesday...
print(next_monday)
Here's a succinct and generic alternative to the slightly weighty answers above.
def onDay(date, day):
"""
Returns the date of the next given weekday after
the given date. For example, the date of next Monday.
NB: if it IS the day we're looking for, this returns 0.
consider then doing onDay(foo, day + 1).
"""
days = (day - date.weekday() + 7) % 7
return date + datetime.timedelta(days=days)
Try
>>> dt = datetime(2011, 7, 2)
>>> dt + timedelta(days=(7 - dt.weekday()))
datetime.datetime(2011, 7, 4, 0, 0)
using, that the next monday is 7 days after the a monday, 6 days after a tuesday, and so on, and also using, that Python's datetime type reports monday as 0, ..., sunday as 6.
This is example of calculations within ring mod 7.
import datetime
def next_day(given_date, weekday):
day_shift = (weekday - given_date.weekday()) % 7
return given_date + datetime.timedelta(days=day_shift)
now = datetime.date(2018, 4, 15) # sunday
names = ['monday', 'tuesday', 'wednesday', 'thursday', 'friday',
'saturday', 'sunday']
for weekday in range(7):
print(names[weekday], next_day(now, weekday))
will print:
monday 2018-04-16
tuesday 2018-04-17
wednesday 2018-04-18
thursday 2018-04-19
friday 2018-04-20
saturday 2018-04-21
sunday 2018-04-15
As you see it's correctly give you next monday, tuesday, wednesday, thursday friday and saturday. And it also understood that 2018-04-15 is a sunday and returned current sunday instead of next one.
I'm sure you'll find this answer extremely helpful after 7 years ;-)
Another alternative uses rrule
from dateutil.rrule import rrule, WEEKLY, MO
from datetime import date
next_monday = rrule(freq=WEEKLY, dtstart=date.today(), byweekday=MO, count=1)[0]
rrule docs: https://dateutil.readthedocs.io/en/stable/rrule.html
Another simple elegant solution is to use pandas offsets.
I find it very helpful and robust when playing with dates.
If you want the first Sunday just modify the frequency to freq='W-SUN'.
If you want a couple of next Sundays, change the offsets.Day(days).
Using pandas offsets allow you to ignore holidays, work only with Business Days and more.
You can also apply this method easily on a whole DataFrame using the apply method.
import pandas as pd
import datetime
# 1. Getting the closest monday from a given date
date = datetime.date(2011, 7, 2)
closest_monday = pd.date_range(start=date, end=date + pd.offsets.Day(6), freq="W-MON")[
0
]
# 2. Adding a 'ClosestMonday' column with the closest monday for each row in
# a pandas df using apply. Requires you to have a 'Date' column in your df
def get_closest_monday(row):
return pd.date_range(
start=row.Date, end=row.Date + pd.offsets.Day(6), freq="W-MON"
)[0]
df = pd.DataFrame([datetime.date(2011, 7, 2)], columns=["Date"])
df["ClosestMonday"] = df.apply(lambda row: get_closest_monday(row), axis=1)
print(df)
You can start adding one day to date object and stop when it's monday.
>>> d = datetime.date(2011, 7, 2)
>>> while d.weekday() != 0: #0 for monday
... d += datetime.timedelta(days=1)
...
>>> d
datetime.date(2011, 7, 4)
import datetime
d = datetime.date(2011, 7, 2)
while d.weekday() != 0:
d += datetime.timedelta(1)
dateutil has a special feature for this kind of operation and it's the most elegant way I have ever seen yet.
from datetime import datetime
from dateutil.relativedelta import relativedelta, MO
first_monday_date = (datetime(2011,7,2) + relativedelta(weekday=MO(0))).date()
if you want datetime just
first_monday_date = datetime(2011,7,2) + relativedelta(weekday=MO(0))
weekday = 0 ## Monday
dt = datetime.datetime.now().replace(hour=0, minute=0, second=0) ## or any specific date
days_remaining = (weekday - dt.weekday() - 1) % 7 + 1
next_dt = dt + datetime.timedelta(days_remaining)
Generally to find any date from day of week from today:
def getDateFromDayOfWeek(dayOfWeek):
week_days = ["monday", "tuesday", "wednesday",
"thursday", "friday", "saturday", "sunday"]
today = datetime.datetime.today().weekday()
requiredDay = week_days.index(dayOfWeek)
if today>requiredDay:
noOfDays=7-(today-requiredDay)
print("noDays",noOfDays)
else:
noOfDays = requiredDay-today
print("noDays",noOfDays)
requiredDate = datetime.datetime.today()+datetime.timedelta(days=noOfDays)
return requiredDate
print(getDateFromDayOfWeek('sunday').strftime("%d/%m/%y"))
Gives output in format of Day/Month/Year
This will give the first next Monday after given date:
import datetime
def get_next_monday(year, month, day):
date0 = datetime.date(year, month, day)
next_monday = date0 + datetime.timedelta(7 - date0.weekday() or 7)
return next_monday
print get_next_monday(2011, 7, 2)
print get_next_monday(2015, 8, 31)
print get_next_monday(2015, 9, 1)
2011-07-04
2015-09-07
2015-09-07
via list comprehension?
from datetime import *
[datetime.today()+timedelta(days=x) for x in range(0,7) if (datetime.today()+timedelta(days=x)).weekday() % 7 == 0]
(0 at the end is for next monday, returns current date when run on monday)

Categories