티스토리 뷰

pandas

영업일(bdate_range, is_busday, weekmask)

데이터조이 2022. 7. 15. 16:20

영업일 (Business day, working day)

시작 날짜부터 끝 날짜까지 총 몇 일의 working day가 있는지 카운트

pd.bdate_range

import datetime
import pandas as pd
holidays_list = ['2022-05-05', '2022-05-08', '2022-06-01', '2022-06-06']
start_date = datetime.datetime.strptime('2022-05-01', "%Y-%m-%d").date()
end_date = datetime.datetime.strptime('2022-05-30', "%Y-%m-%d").date()
print (len(pd.bdate_range(start=start_date, end=end_date, freq='C', holidays=holidays_list)))

freq='C' 는 custom된 freq를 사용하겠다는 의미. weekmask나 holidays를 따로 사용해 주었을 경우 freq='C'라고 적어주어야함. 

디폴트는 'B' (business daily)

 

[함수형태]

def foo(row):
    start_date = row['시작일']
    end_date = row['끝일']
    l = len(pd.bdate_range(start=start_date, end=end_date, freq='C', holidays=holidays_list)))
    return l
df['시작일'] = pd.to_datetime(df['시작일'], format='%Y%m%d')
df['끝일'] = pd.to_datetime(df['끝일'], format='%Y%m%d')
df['시작일-끝일'] = df.apply(foo, axis=1)

 

다음 영업일 찾기

np.is_busday

ONE_DAY = datetime.timedelta(days=1)

def next_business_day():
    # today = datetime.date.today()
    today = datetime.datetime.strptime('2022-07-08', "%Y-%m-%d").date()
    next_day = today + ONE_DAY
    while next_day in holidays_list_date or not np.is_busday(next_day):
        next_day += ONE_DAY
    return next_day

Data Frame에 적용 + lead time(지역별 배송 소요시간) 고려

ONE_DAY = datetime.timedelta(days=1)

def next_business_day_lead_time(row):
    start_str = row['출고완료일']
    lead_day = row['지역별배송소요시간'] / 24
    cal_lead_day = datetime.timedelta(days=lead_day)  # 이틀
    exp_dlv_day = start_str + cal_lead_day
    while exp_dlv_day in holidays_list_date or not np.is_busday(exp_dlv_day):
        exp_dlv_day += ONE_DAY
    return exp_dlv_day

df['출고완료일_소요시간'] = df.apply(next_business_day_lead_time, axis=1)

Data Frame에 적용 + weekmask 사용법 (토요일만 휴무일인 경우)

def cal_exp_dlv_date2(row, time_threshold):
    start_str = row['입금확인일']
    if row['입금확인시간'] >= datetime.datetime.strptime(time_threshold, '%H:%M:%S').time():  # time만 원하면 .time()
        lead_day = 1
    else:
        lead_day = 0
    exp_dlv_day = start_str.date()
    # 입금확인일이 토요일인 경우 하루 추가.
    if exp_dlv_day in holidays_list_date or not np.is_busday(exp_dlv_day, weekmask=[1, 1, 1, 1, 1, 0, 1]):
        exp_dlv_day += ONE_DAY
        while exp_dlv_day in holidays_list_date or not np.is_busday(exp_dlv_day, weekmask=[1, 1, 1, 1, 1, 0, 1]):
            exp_dlv_day += ONE_DAY
    for i in range(int(lead_day)):
        exp_dlv_day += ONE_DAY
        while exp_dlv_day in holidays_list_date or not np.is_busday(exp_dlv_day, weekmask=[1, 1, 1, 1, 1, 0, 1]):
            exp_dlv_day += ONE_DAY
    return exp_dlv_day

new_df['출고예정일자_new'] = new_df.apply(cal_exp_dlv_date2, time_threshold='21:00:00', axis=1)

holidays_list_date = [내가 정한 공휴일]

 

함수 설명: 

- 만약 입금확인 시간이 21시 이상인 경우 lead_day는 1일, 아니면 0일

- exp_dlv_day라는 변수에 입금확인일의 날짜만 넣어줌.

- 만약, exp_dlv_day가 holidays_list_date/토요일일 경우 하루씩 추가해주면서 exp_dlv_day가 holidays_list_date/토요일이 아니게 만듦.

- 그리고 나서 위에서 구한 lead_day를 이용해 lead_day만큼 더해가면서 exp_dlv_day가 holidays_list_date/토요일이 아니게 만듦. 

- 최종적으로 구해진 exp_dlv_day값 리턴. 

댓글
Total
Today
Yesterday
공지사항
최근에 올라온 글
글 보관함