Split the date into 1st, 2nd, 3rd, 4th week of the month - python-3.x

I have a data frame of dates:
id|date
13|2017-01-31
12|2016-12-07
11|2013-03-19
I want to classify the dates into weather it is the 1st, 2nd, 3rd or 4th week of the month.
I am using this function:
calendar.setfirstweekday(calendar.SUNDAY)
def get_week_of_month(dt):
year = dt.year
month = dt.month
day = dt.day
x = np.array(calendar.monthcalendar(year, month))
week_of_month = np.where(x==day)[0][0] + 1
return(week_of_month)
df['week_month'] = df['date'].apply(get_week_of_month)
However I am getting 6 possible weeks instead of 4. Please help

Like this:
In [1036]: df['date']= pd.to_datetime(df['date'])
In [1044]: df['week_of_month'] = ((df['date'].dt.day-1)//7)+1
In [1045]: df
Out[1045]:
id date week_of_month
0 13 2017-01-31 5
1 12 2016-12-07 1
2 11 2013-03-19 3

Related

using week number to get range of dates with sunday as first day of week in python

input: week_number = 34 (or 2022-34)
expected output:
["2022-08-21","2022-08-22", "2022-08-23","2022-08-24","2022-08-25","2022-08-26","2022-08-27"]
First date should be of Sunday
the last date should be Saturday
work with both leap and non leap year
Try:
import datetime
week_number = 34
out = []
date = datetime.datetime.strptime(f"2022-{week_number}-0", "%Y-%U-%w")
for day in range(7):
out.append((date + datetime.timedelta(days=day)).strftime("%Y-%m-%d"))
print(out)
Prints:
[
"2022-08-21",
"2022-08-22",
"2022-08-23",
"2022-08-24",
"2022-08-25",
"2022-08-26",
"2022-08-27",
]
From the reference:
%U - Week number of the year (Sunday as the first day of the week) as
a zero-padded decimal number. All days in a new year preceding the
first Sunday are considered to be in week 0.

Limit max day of Data for all months

I need to calculate, over months, the value of Sales in every month limiting the max day of my data = my Day(DateTimeNow()) - 1.
Examples:
Today is 25 of march, i wanna see in my bar chart the total of Sales until day 24 for january, february and march.
Today is 02 of april, my bar chart will show the sales of day 1 for january, february, march and april.
I've tried using limit data in my graph like so I set the max day of my Date to be the Day(DateTimeNow()) - 1
Max(Day([DATE])) = Day(DateTimeNow()) - 1
That way I set the max Day for my date to be equal my Day - 1
I've tried using ParallelPeriod too.
I expect that using:
Max(Day([DATE])) = Day(DateTimeNow()) - 1
I've got like:
Max(Day([DATE])) = 31
Day(DateTimeNow()) - 1 = 02
( Max(Day([DATE])) = Day(DateTimeNow()) - 1 )
I know that this results in a boolean expression, so:
31 = 02 -> False
But i just want to set the Max Day to be 02.
This expression below should fit your needs. Put this expression in the Limit data using expression of the visualization options.
Day([DATE])<Day(DateTimeNow())-1
It takes, for each months, the days before current day - 1. If we are on the first of the month, then no data will be available.

find the last business date for June and Dec of any given year in Python

I want to find the last business day for the month of June and Dec for 2019. my below code gives me the last business day for last month and the current month. Ideally i want a code which allows me to input a year and month and it will tell me the last business day for the month and year i input.
i want my output to be like this for June 2019 and Dec 2019
2906
3112
hope someone can help me here, thanks
from pandas.tseries.offsets import BMonthEnd
from datetime import date
d=date.today()
offset = BMonthEnd()
#Last day of current month
current_month = offset.rollforward(d)
print(current_month)
#Last day of previous month
last_month = offset.rollback(d)
print(last_month)
Here's a function that will find the last weekday in a given month and format it as a string in the format given
import datetime
def last_weekday(year, month):
# Add a month
if month == 12:
month = 1
year += 1
else:
month += 1
d = datetime.date(year, month, 1)
# Subtract a day
d -= datetime.timedelta(days=1)
# Subtract more days if we have a weekend
while d.weekday() >= 5:
d -= datetime.timedelta(days=1)
return '{:02d}{:02d}'.format(d.month, d.day)
# Examples:
last_weekday(2019, 6) # -> '0628'
last_weekday(2019, 12) # -> '1231'

Pandas to recognize current date, and filter a date column relative to today's date

Having a lot of trouble translating the logic below in pandas/python, so I do not even have sample code or a df to work with :x
I run a daily report, that essentially filters for data from Monday thru the day before what 'Today' is. I have a Date column [ in dt.strftime('%#m/%#d/%Y') format] . It will never be longer than a Monday-Sunday scope.
1) Recognize the day it is 'today' when running the report, and recognize what day the closet Monday prior was. Filter the "Date" Column for the Monday-day before today's date [ in dt.strftime('%#m/%#d/%Y') format ]
2) Once the df is filtered for that, take this group of rows that have dates in the logic above, have it check for dates in a new column "Date2". If any dates are before the Monday Date, in Date2, change all of those earlier dates in 'Date2' to the Monday date it the 'Date' column.
3) If 'Today' is a Monday, then filter the scope from the Prior Monday through - Sunday in the "Date" Column. While this is filtered, do the step above [step 2] but also, for any dates in the "Date2" column that are Saturday and Sunday Dates - changes those to the Friday date.
Does this make sense?
Here're the steps:
from datetime import datetime
today = pd.to_datetime(datetime.now().date())
day_of_week = today.dayofweek
last_monday = today - pd.to_timedelta(day_of_week, unit='d')
# if today is Monday, we need to step back another week
if day_of_week == 0:
last_monday -= pd.to_timedelta(7, unit='d')
# filter for last Monday
last_monday_flags = (df.Date == last_mon)
# filter for Date2 < last Monday
date2_flags = (df.Date2 < last_monday)
# update where both flags are true
flags = last_monday_flags & date2_flags
df.loc[flags, 'Date2'] = last_monday
# if today is Monday
if day_of_week == 0:
last_sunday = last_monday + pd.to_timedelta(6, unit='d')
last_sat = last_sunday - pd.to_timedelta(1, unit='d')
last_week_flags = (df.Date >= last_monday) & (df.Date <= next_sunday)
last_sat_flags = (df.Date2 == last_sat)
last_sun_flags = (df.Date2 == last_sun)
# I'm just too lazy and not sure how Sat and Sun relates to Fri
# but i guess just subtract 1 day or 2 depending on which day
...

Number of days in between given two dates treating number of days in month as fixed 30 days

I need to calculate difference between two dates with a fixed 30 days a month logic. The example is shown below
Start date = 10/4/2018
End date = 28/10/2018
Expected number of days between = 199
(Excel calculation of difference of days => 28/10/2018 - 10/4/2018 = 201 which is not what I need)
The basis for calculation of difference between two dates is, it should consider number of days in a month as 30 days irrespective of the month. So all months in between the start & end dates with 31 days should be treated as 30 days. If there is Feb in between, it should also be taken as 30 days month.
Procedure to calculate number of days in between two given dates:
Fraction of days in the starting month = 30/4/2018 - 10/4/2018 = 21 days
Months in between 1/5/2018 to 30/9/2018 = 5 months = 5 x 30 = 150 days
Fraction of days in the last month = 28/10/2018 - 1/10/2018 = 28 days
Total days = 21 + 150 + 28 = 199 days.
If A1 is start date cell, B1 = End date cell, please suggest how to do it in excel.
I've broken the formula into the three components as in your example:
The formulas in D2:G2 are:
D2: =IF(AND(YEAR(A2)=YEAR(B2),MONTH(A2)=MONTH(B2)),MIN(DATE(YEAR(A2),MONTH(A2),30),B2),DATE(YEAR(A2),MONTH(A2),30))-MIN(DATE(YEAR(A2),MONTH(A2),30),A2)+1
E2: =MAX(((YEAR(B2)-YEAR(A2))*12+MONTH(B2)-MONTH(A2)-1)*30,0)
F2: =MIN(IF(AND(YEAR(B2)=YEAR(A2),MONTH(B2)=MONTH(A2)),0,B2-DATE(YEAR(B2),MONTH(B2),1)+1),30)
G2: =SUM(D2:F2)
or, all in one:
=IF(AND(YEAR(A2)=YEAR(B2),MONTH(A2)=MONTH(B2)),MIN(DATE(YEAR(A2),MONTH(A2),30),B2),DATE(YEAR(A2),MONTH(A2),30))-MIN(DATE(YEAR(A2),MONTH(A2),30),A2)+1+MAX(((YEAR(B2)-YEAR(A2))*12+MONTH(B2)-MONTH(A2)-1)*30,0)+MIN(IF(AND(YEAR(B2)=YEAR(A2),MONTH(B2)=MONTH(A2)),0,B2-DATE(YEAR(B2),MONTH(B2),1)+1),30)
I like the elegance of #Jeeped 's code, but this might be easier to follow.
Try this,
=SUMPRODUCT(--(DAY(ROW(INDIRECT(A2&":"&B2)))<>31))+
(DAY(A2)=31)+
SIGN(SUMPRODUCT((MONTH(ROW(INDIRECT(A2&":"&B2)))=2)*(DAY(ROW(INDIRECT(A2&":"&B2)))=28)))*2
It seems to me that your examples are a little "wonky", like how the 31st counts sometimes (like if it's the start/end date) but not others.
Anyway, this function ain't pretty but it does the trick:
Function No31st(startDate As Date, endDate As Date) As Long
Dim d As Date
For d = startDate To endDate 'iterate each day in range
If Day(d) <= 30 Then 'count days up to the 30th
No31st = No31st + 1
'if it's Feb 28, add 2 more days
If (Month(d) = 2 And Day(d) = 28) Then
No31st = No31st + 2 ' + Feb 29 + Feb 30
If Day(d + 1) <> 1 Then d = d + 1 'leap year
End If
End If
Next d
'since the 31st counts if it's the last day:
If Day(startDate) = 31 Or Day(endDate) = 31 Then No31st = No31st + 1
End Function
Sample Output:
StartDate endDate result
10/4/2018 28/10/2018 199
31/1/2018 31/3/2018 61
28/2/2018 1/3/2018 4
28/2/2000 1/3/2000 4
31/1/2018 1/2/2018 2
The DAYS360 formula is based on the 12 30-day month logic.
Simple & Easy Ways:
(1)
=YEARFRAC(start_date,end_date,4)*360
(2)
=DAYS360(start_date,end_date)

Resources