파이썬을 활용하여 당일 기준 전 영업일을 계산하는 로직을 만들어보자.
전영업일 : 주말+휴일을 제외하고 영업일 기준으로 전일자.
Ex) 2023.5.8의 전영업일은 2023.5.4일이다.
한국 공휴일은 매년 달라지므로 공공데이터 포털 API를 활용하여 정보를 받아오도록 하자.
아래 작업을 수행하기 위해서는 먼저 회원가입을 해야한다.
회원가입이 완료되었다면 로그인 후 아래 사이트에 접근한다.
https://www.data.go.kr/tcs/dss/selectApiDataDetailView.do?publicDataPk=15012690
[한국천문연구원_특일 정보] 내 [활용 신청]을 클릭하여 양식대로 작성한다.
(실시간으로 승인이 완료된 것으로 보아 작성 내용을 검수하지는 않는 것 같다.)
[활용신청]이 완료되었다면 우측 상단의 [마이페이지]로 이동한다.
[마이페이지]-[데이터활용]-[Open API] - [활용신청 현황] 에서 신청내역을 확인할 수 있다.
해당 페이지에서 [한국천문연구원_특일 정보]를 클릭하면 아래와 같이 인증키 정보를 확인할 수 있다.(
활용기간은 2년)
[한국천문연구원_특일 정보]에서 확인한 일반 인증키로 아래와 같이 코드를 작성한다.
import 가 정상적으로 되지 않는 경우 cmd를 실행하여 아래 명령어를 실행한다.
- pip install pandas
- pip install requests
from datetime import datetime, date, timedelta
import pandas as pd
import requests
import json
from pandas import json_normalize
class KoreaHolidays:
def get_holidays(self):
today = datetime.today().strftime("%Y%m%d")
today_year = datetime.today().year
KEY = "인증키 입력"
url = (
"http://apis.data.go.kr/B090041/openapi/service/SpcdeInfoService/getRestDeInfo?_type=json&numOfRows=50&solYear="
+ str(today_year)
+ "&ServiceKey="
+ str(KEY)
)
response = requests.get(url)
if response.status_code == 200:
json_ob = json.loads(response.text)
holidays_data = json_ob["response"]["body"]["items"]["item"]
dataframe = json_normalize(holidays_data)
# dateName = dataframe.loc[dataframe["locdate"] == int(today), "dateName"]
# print(dateName)
return dataframe["locdate"].to_list()
today_year = datetime.today().year 를 통해 당해년도를 추출한다.
그리고 아래와 같이 URL을 호출하여 공휴일 정보를 받아오게된다.
2023년을 기준으로 호출 시 아래와 같이 공휴일 데이터가 불려온다.
{"response":{"header":{"resultCode":"00","resultMsg":"NORMAL SERVICE."},"body":{"items":{"item":[{"dateKind":"01","dateName":"1월1일","isHoliday":"Y","locdate":20230101,"seq":1},{"dateKind":"01","dateName":"설날","isHoliday":"Y","locdate":20230121,"seq":1},{"dateKind":"01","dateName":"설날","isHoliday":"Y","locdate":20230122,"seq":1},{"dateKind":"01","dateName":"설날","isHoliday":"Y","locdate":20230123,"seq":1},{"dateKind":"01","dateName":"대체공휴일","isHoliday":"Y","locdate":20230124,"seq":1},{"dateKind":"01","dateName":"삼일절","isHoliday":"Y","locdate":20230301,"seq":1},{"dateKind":"01","dateName":"어린이날","isHoliday":"Y","locdate":20230505,"seq":1},{"dateKind":"01","dateName":"부처님오신날","isHoliday":"Y","locdate":20230527,"seq":1},{"dateKind":"01","dateName":"현충일","isHoliday":"Y","locdate":20230606,"seq":1},{"dateKind":"01","dateName":"광복절","isHoliday":"Y","locdate":20230815,"seq":1},{"dateKind":"01","dateName":"추석","isHoliday":"Y","locdate":20230928,"seq":1},{"dateKind":"01","dateName":"추석","isHoliday":"Y","locdate":20230929,"seq":1},{"dateKind":"01","dateName":"추석","isHoliday":"Y","locdate":20230930,"seq":1},{"dateKind":"01","dateName":"개천절","isHoliday":"Y","locdate":20231003,"seq":1},{"dateKind":"01","dateName":"한글날","isHoliday":"Y","locdate":20231009,"seq":1},{"dateKind":"01","dateName":"기독탄신일","isHoliday":"Y","locdate":20231225,"seq":1}]},"numOfRows":50,"pageNo":1,"totalCount":16}}}
해당 데이터를 dataframe["locdate"].to_list() 을 통해 리스트 형태로 바꿔줍니다.
여기까지가 공휴일데이터를 받아오는 과정입니다.
이제 받아온 공휴일 정보를 활용하여 휴일 여부를 검증하는 oldday_is_holiday() 메소드를 생성해봅시다.
해당 메소드를 통하여 공휴일 API를 호출하고 올해의 공휴일 정보를 받아올 수 있습니다.
def oldday_is_holiday(tmp_date):
tmp_date = tmp_date.strftime("%Y%m%d")
holidays = koreaHolidays.get_holidays()
is_holiday = False
if int(tmp_date) in holidays:
is_holiday = True
return is_holiday
oldday_is_holiday(tmp_date) : 해당 메소드 호출 시 전달값인 tmp_date를 기준으로 아래의 메소드를 실행합니다.
1) 위의 호출한 공휴일 데이터를 holidays 변수에 저장합니다.
2) 전달받은 tmp_date가 holidays 안에 포함된 날짜인지 검증합니다.
3) 만약 tmp_date가 holidays 안에 없는 날짜이면 false를,
tmp_date가 holidays 안에 포함된 날짜이면 true를 반환합니다.
그런데 위의 공휴일 API에는 5/1일 근로자의 날이 불포함되어 있습니다.
이외에도 창립기념일 등 예외적인 휴일이 발생될 수 있습니다.
이러한 경우에는 위 데이터에 특정일자를 아래와 같이 추가하였습니다.
workersday = str(datetime.today().year) + "0501"
workersday = int(workersday)
def oldday_is_holiday(tmp_date):
tmp_date = tmp_date.strftime("%Y%m%d")
holidays = koreaHolidays.get_holidays()
holidays.append(workersday)
# holidays.append(20220908)
is_holiday = False
if int(tmp_date) in holidays:
is_holiday = True
return is_holiday
공휴일 데이터 받아온 후 특정 휴일 데이터 추가하여 holidays 변수에 저장한 후
tmp_date값이 holidays 데이터 내에 있는 경우 is_holiday : true 반환
tmp_date값이 holidays 데이터 내에 없는 경우 is_holiday : false 반환하는 것 까지 설정해보았습니다.
이제 위에서 만들었던 메소드와 변수를 이용해 실제 전 영업일을 구해오도록 해보겠습니다.
tmp_date = date.today() - timedelta(1)
koreaHolidays = KoreaHolidays()
is_holiday_result = oldday_is_holiday(tmp_date)
tmp_date = date.today() - timedelta(1) // 오늘 날짜에서 하루 전날을 tmp_date로 설정합니다.
is_holiday_result = oldday_is_holiday(tmp_date) // tmp_date를 holidays와 비교하여 반환된 true/false값을 입력합니다.
이때 전일자가 주말이거나, 휴일인 경우에 tmp_date는 -1 처리가 반복적으로 수행됩니다.
while True:
if(tmp_date.weekday()>=5) or (is_holiday_result):
tmp_date = tmp_date-timedelta(1)
is_holiday_result = oldday_is_holiday(tmp_date)
else:
break
반복문 조건1)
tmp_date.weekday() : 날짜.weekday()의 값이 5나 6인 경우 토요일이나 일요일에 해당됩니다.
tmp_date.weekday()>=5 조건을 통하여 tmp_date가 주말인지 여부를 확인합니다.
반복문 조건2)
is_holiday_result : oldday_is_holiday(tmp_date) 비교하여 반환된 true/false 값을 확인합니다.
tmp_date가 holidays에 포함되었는지 여부를 체크합니다.
위 조건 1,2 중 하나라도 성립된다면 tmp_date는 -1일 처리됩니다.
-1일 처리된 tmp_date로 다시 주말여부와 공휴일 여부를 체크하여 적용합니다.
두개의 조건이 모두 false로 응답받게 되면 반복문을 종료됩니다.
즉 주말이나 휴일을 제외한 전영업일자를 확인할 수 있습니다.
완성된 전체 코드는 아래와 같습니다.
from datetime import datetime, date, timedelta
import pandas as pd
import requests
import json
from pandas import json_normalize
class KoreaHolidays:
def get_holidays(self):
today = datetime.today().strftime("%Y%m%d")
today_year = datetime.today().year
KEY = "kpMdx2%2FvhonYM%2FfE0PxjZelH62Up%2Fg8PL0RaNeO4fRaqjE%2F32RxBeVaPtcx0yEa5MY2WZ7WftTQeZJF5dZec3A%3D%3D"
url = (
"http://apis.data.go.kr/B090041/openapi/service/SpcdeInfoService/getRestDeInfo?_type=json&numOfRows=50&solYear="
+ str(today_year)
+ "&ServiceKey="
+ str(KEY)
)
response = requests.get(url)
if response.status_code == 200:
json_ob = json.loads(response.text)
holidays_data = json_ob["response"]["body"]["items"]["item"]
dataframe = json_normalize(holidays_data)
# dateName = dataframe.loc[dataframe["locdate"] == int(today), "dateName"]
# print(dateName)
return dataframe["locdate"].to_list()
workersday = str(datetime.today().year) + "0501"
workersday = int(workersday)
def oldday_is_holiday(tmp_date):
tmp_date = tmp_date.strftime("%Y%m%d")
holidays = koreaHolidays.get_holidays()
holidays.append(workersday)
# holidays.append(20220908)
is_holiday = False
if int(tmp_date) in holidays:
is_holiday = True
return is_holiday
#In[2]
tmp_date = date.today() - timedelta(1)
koreaHolidays = KoreaHolidays()
is_holiday_result = oldday_is_holiday(tmp_date)
# In[3]:
while True:
if(tmp_date.weekday()>=5) or (is_holiday_result):
tmp_date = tmp_date-timedelta(1)
is_holiday_result = oldday_is_holiday(tmp_date)
else:
break
print(date.today())
print(tmp_date)
'Spec UP - Frontend > 도전! 프로젝트' 카테고리의 다른 글
주문 페이지 (0) | 2021.12.22 |
---|---|
Java-이름 출력 (0) | 2021.12.14 |
JavaScript를 이용한 계산기 만들기(addEventListener) (0) | 2021.10.21 |
JavaScript를 이용한 나이 계산기(출생연도) (0) | 2021.10.21 |
How TO - Side Navigation (0) | 2021.10.19 |
댓글