I have an set of stock information, with datetime set as index, stock market only open on weekdays so all my rows are weekdays, which is fine, I would like to determine if a row is start of the week or end of week, which might NOT always fall on Monday/Friday due to holidays. A better idea is to determine if there is an row entry on the next/previous day in the dataframe ( since my data is guaranteed to only exist for workday), but I dont know how to calculate this. Here is an example of my data:

date    day_of_week day_of_month    day_of_year month_of_year
5/1/2017    0   1   121 5
5/2/2017    1   2   122 5
5/3/2017    2   3   123 5
5/4/2017    3   4   124 5
5/8/2017    0   8   128 5
5/9/2017    1   9   129 5
5/10/2017   2   10  130 5
5/11/2017   3   11  131 5
5/12/2017   4   12  132 5
5/15/2017   0   15  135 5
5/16/2017   1   16  136 5
5/17/2017   2   17  137 5
5/18/2017   3   18  138 5
5/19/2017   4   19  139 5
5/23/2017   1   23  143 5
5/24/2017   2   24  144 5
5/25/2017   3   25  145 5
5/26/2017   4   26  146 5
5/30/2017   1   30  150 5

Here is my current code

# Date fields
def DateFields(df_input):
    dates = df_input.index.to_series()  
    df_input['day_of_week'] = dates.dt.dayofweek
    df_input['day_of_month'] = dates.dt.day
    df_input['day_of_year'] = dates.dt.dayofyear
    df_input['month_of_year'] = dates.dt.month
    df_input['isWeekStart'] = "No" #<--- Need help here
    df_input['isWeekEnd'] = "No" #<--- Need help here
    df_input['date'] = dates.dt.strftime('%Y-%m-%d')
    return df_input

How can I calculate if a row is beginning of week and end of week?

Example of what I am looking for:

date    day_of_week day_of_month    day_of_year month_of_year isWeekStart isWeekEnd
5/1/2017    0   1   121 5   1   0
5/2/2017    1   2   122 5   0   0
5/3/2017    2   3   123 5   0   0
5/4/2017    3   4   124 5   0   1 # short week, Thursday is last work day
5/8/2017    0   8   128 5   1   0
5/9/2017    1   9   129 5   0   0
5/10/2017   2   10  130 5   0   0
5/11/2017   3   11  131 5   0   0
5/12/2017   4   12  132 5   0   1
5/15/2017   0   15  135 5   1   0
5/16/2017   1   16  136 5   0   0
5/17/2017   2   17  137 5   0   0
5/18/2017   3   18  138 5   0   0
5/19/2017   4   19  139 5   0   1
5/23/2017   1   23  143 5   1   0 # short week, Tuesday is first work day
5/24/2017   2   24  144 5   0   0
5/25/2017   3   25  145 5   0   0
5/26/2017   4   26  146 5   0   1
5/30/2017   1   30  150 5   1   0

EDIT: I forgot that some holidays fall during the middle of week, in this situation, it would be good if it can treat these as a separate “week” with before and after marked accordingly. Although if it’s not smart enough to figure this out, just getting the long weekend would be a good start.

Answer

Here’s an idea with BusinessDay:

prev_working_day = df['date'] - pd.tseries.offsets.BusinessDay(1)

df['isFirstWeekDay'] = (df['date'].dt.isocalendar().week != 
                        prev_working_day.dt.isocalendar().week)

And similar for last business day. Note that the default holiday calendar is US’. Check out this post for a different one.

Output:

         date  day_of_week  day_of_month  day_of_year  month_of_year  isFirstWeekDay
0  2017-05-01            0             1          121              5            True
1  2017-05-02            1             2          122              5           False
2  2017-05-03            2             3          123              5           False
3  2017-05-04            3             4          124              5           False
4  2017-05-08            0             8          128              5            True
5  2017-05-09            1             9          129              5           False
6  2017-05-10            2            10          130              5           False
7  2017-05-11            3            11          131              5           False
8  2017-05-12            4            12          132              5           False
9  2017-05-15            0            15          135              5            True
10 2017-05-16            1            16          136              5           False
11 2017-05-17            2            17          137              5           False
12 2017-05-18            3            18          138              5           False
13 2017-05-19            4            19          139              5           False
14 2017-05-23            1            23          143              5           False
15 2017-05-24            2            24          144              5           False
16 2017-05-25            3            25          145              5           False
17 2017-05-26            4            26          146              5           False
18 2017-05-30            1            30          150              5           False

Source: https://stackoverflow.com/q/67596703

172 2 2 0