1 votes

Exclude weekends from a date range Python

I need to skip weekends. In my code I convert a date in str to datetime, then I enter the number of days I want to add. What I am looking for is that in the variable end the weekends are excluded.

import datetime
from datetime import timedelta

inicio = datetime.datetime.strptime('01/01/2009', '%d/%m/%Y')
fin = inicio + datetime.timedelta(+2500)

2voto

FJSevilla Points 29084

To filter the dates you can use the attribute weekday which returns the day of the week (Monday is 0 and Sunday is 6) and check if it is less than 5 or isoweekday (Monday is 1 and Sunday is 7) and check that it is less than 6:

inicio = datetime.datetime.strptime('01/01/2009', '%d/%m/%Y')
dias = 2500

dates = []
for days in range(dias):
    date = inicio + datetime.timedelta(days=days)
    if date.weekday() < 5:
        dates.append(date)

If you already have a list of dates and want to exclude those that are weekends, the idea is the same:

import datetime

fechas = [datetime.datetime(2019, 7, 19),
          datetime.datetime(2019, 7, 20),
          datetime.datetime(2019, 7, 21),
          datetime.datetime(2019, 7, 22)]

fechas_lab = [fecha for fecha in fechas if fecha.weekday() < 5]
>>> fechas_lab
[datetime.datetime(2019, 7, 19, 0, 0), datetime.datetime(2019, 7, 22, 0, 0)]

However, I recommend you to use pandas to generate the date range, for example you can get what you want with pandas.date_range using as "B" period (business day) or directly with pandas.bdate_range :

import pandas as pd

inicio = pd.datetime.strptime('01/01/2009', '%d/%m/%Y')
dt = pd.bdate_range(start=inicio, periods=dias, freq="D")

You can use a date as a deadline as well:

import pandas as pd

inicio = pd.datetime.strptime('01/01/2009', '%d/%m/%Y')
fin = pd.datetime.strptime('01/01/2011', '%d/%m/%Y')

dt = pd.bdate_range(start=inicio, end=fin, freq="D")

Example:

import pandas as pd

inicio = pd.datetime.strptime('19/07/2019', '%d/%m/%Y')
fin = pd.datetime.strptime('31/07/2019', '%d/%m/%Y')

dt = pd.bdate_range(start=inicio, end=fin)
>>> dt

DatetimeIndex(['2019-07-19', '2019-07-22', '2019-07-23', '2019-07-24',
               '2019-07-25', '2019-07-26', '2019-07-29', '2019-07-30',
               '2019-07-31'],
              dtype='datetime64[ns]', freq='B')

As can be seen, 20, 21, 27 and 28 are missing.

If we do not want to use it as an index we can obtain a Series, a NumPy array, a list, etc. using the methods to_series() , to_numpy() , to_list() etc.

>>> dt.to_numpy()

array(['2019-07-19T00:00:00.000000000', '2019-07-22T00:00:00.000000000',
       '2019-07-23T00:00:00.000000000', '2019-07-24T00:00:00.000000000',
       '2019-07-25T00:00:00.000000000', '2019-07-26T00:00:00.000000000',
       '2019-07-29T00:00:00.000000000', '2019-07-30T00:00:00.000000000',
       '2019-07-31T00:00:00.000000000'], dtype='datetime64[ns]')

If you want to filter existing data you have multiple options.

If you have a DataFrame with DateTimeIndex as index or a time series you want to keep only the working days you can make use of the method asfreq :

import pandas as pd

df = pd.DataFrame({"fecha": (pd.datetime(2019, 7, 19),
                             pd.datetime(2019, 7, 20),
                             pd.datetime(2019, 7, 21),
                             pd.datetime(2019, 7, 22)
                             ),
                   "col_dummy": (1, 2, 3, 5)
                  })

df.set_index("fecha", inplace=True)
>>> df
             col_dummy
fecha 
2019-07-19   1
2019-07-20   2
2019-07-21   3
2019-07-22   5

>>> df.asfreq(pd.tseries.offsets.BDay())

             col_dummy
fecha
2019-07-19   1
2019-07-22   5

If it is not an index, but a series or column of type datetime you can filter in several ways, for example using the same method as with datetime in standard Python:

import pandas as pd

df = pd.DataFrame({"fecha": (pd.datetime(2019, 7, 19),
                             pd.datetime(2019, 7, 20),
                             pd.datetime(2019, 7, 21),
                             pd.datetime(2019, 7, 22)
                             ),
                   "col_dummy": (1, 2, 3, 5)
                  })
>>> df
        fecha  col_dummy
0  2019-07-19          1
1  2019-07-20          2
2  2019-07-21          3
3  2019-07-22          5

>>> df.loc[df["fecha"].dt.weekday < 5]

        fecha  col_dummy
1  2019-07-19          1
3  2019-07-22          5

or by using the pd.datetime.dt.weekday_name together with isin

>>> df.loc[~df["fecha"].dt.weekday_name.isin(['Saturday','Sunday'])]

0 votes

ok and using pandas how do I exclude weekends?

1 votes

The example I give you already generates a DatetimeIndex with only working days, if you want a series you can use the method to_series() , ( pd.bdate_range(start=inicio, end=fin).to_series() ) o to_numpy() for an array of numpy, etc...

HolaDevs.com

HolaDevs is an online community of programmers and software lovers.
You can check other people responses or create a new question if you don't find a solution

Powered by:

X