高校物理160203 views
高校国語788336 views
高校化学2924392 views
雑学1473612 views
高校日本史190571 views
小学社会310485 views
英語613639 views
小学算数1200427 views
りんご209490 views
高校生物551766 views
Help
Tools
NewsSpreadsheetCalendarSlidesTier ListPen ToolIllustrationCrayonPixel ArtASCII ArtPerspectiveEndless StairsGraphMind MapER DiagramFamily TreeMemeCurved TextImage EditorMosaicRetro FilterPencil SketchOCR/HighlighterMakeup EditorFaviconVideo TrimmerScrolling VideoVideo TitleColor PickerColor ExtractorBonfireFireworksWater RippleWater SplashBreaking GlassWood GrainMarble TextureCSS ButtonIcon MakerBar ChartGrouped Bar ChartStacked Bar ChartPie ChartLine ChartArea ChartStacked Area ChartScatter Plot3D Bar Chart3D Pie ChartBar Chart RaceBubble ChartPopulation PyramidPictogramEarningsCandlestick ChartInvestment RiskMortgage SimulatorCalculatorMatrix CalculatorFunction GraphPolynomial ExpansionVenn DiagramField VisualizerRubik's Cube Group TheoryTraveling SalesmanVoronoi and DelaunayFractalColumn ArithmeticDraw Math FiguresArithmetic AnimationArithmetic Word ProblemsCounting with Tree DiagramsCube NetsCross SectionsMotion PathMechanicsWavesLight and LensesThermodynamicsHow Semiconductors WorkMolecular StructuresAtomic OrbitalsElectrochemical CellsChemical EquilibriumCrystal LatticesBuffer pHComplex IonsDNA Double HelixCell DivisionMembrane ChannelsNerve ImpulseRock ClassificationWeatherConstellationsSolar and Lunar Eclipses3D ModelingFloor PlanSeismic StructuresIntersection TurnMaglevCooking AnimationOrigamiLive Viewer CountGeoJSON MapRailway MapPopulation MapCrime MapLand Price MapSchool MapShrine and Castle MapHouse of Representatives MapWord MapSolitaireReversiHakoiri MusumeChessHamburgerRippleSlide Puzzle MakerNeon PinballNovel MakerJapanese Typing PracticePiano Score EditorMusic Theory

English

Python で「営業日」を計算する(祝日・休業日対応)

業務システムでは「3 営業日後」「月末の最終営業日」といった計算が頻繁に必要になります。Python には営業日計算をサポートするライブラリがいくつかありますが、それぞれ特徴が異なります。

numpy の busday 関数

NumPy には営業日計算用の関数が組み込まれています。科学計算ライブラリですが、日付計算にも使えます。

import numpy as np
from datetime import date

# 5営業日後を計算
today = date(2024, 12, 20)  # 金曜日
result = np.busday_offset(today, 5)
print(result)
# 2024-12-27(土日を除いた5営業日後)

busday_offset は土日を自動的にスキップします。祝日を考慮するには holidays パラメータを指定します。

import numpy as np
from datetime import date

# 祝日を指定
holidays = [
    '2024-12-23',  # 天皇誕生日の振替
    '2024-12-31',  # 年末
    '2025-01-01',  # 元日
]

today = date(2024, 12, 20)
result = np.busday_offset(today, 5, holidays=holidays)
print(result)
# 2024-12-30(祝日も除外)

2 つの日付間の営業日数を数えることもできます。

import numpy as np

start = '2024-12-01'
end = '2024-12-31'
count = np.busday_count(start, end)
print(count)
# 22(12月の営業日数、祝日考慮なし)

pandas の営業日オフセット

pandas はより柔軟な営業日計算を提供します。

import pandas as pd
from datetime import date

# BusinessDay オフセット
today = pd.Timestamp(2024, 12, 20)
result = today + pd.offsets.BusinessDay(5)
print(result)
# 2024-12-27 00:00:00

pandas の強みはカスタムカレンダーを定義できる点です。

import pandas as pd
from pandas.tseries.holiday import AbstractHolidayCalendar, Holiday

# 日本の祝日カレンダーを定義
class JapaneseHolidayCalendar(AbstractHolidayCalendar):
    rules = [
        Holiday('元日', month=1, day=1),
        Holiday('成人の日', month=1, day=8),  # 第2月曜
        Holiday('建国記念の日', month=2, day=11),
        # ... 他の祝日を追加
    ]

# カスタムカレンダーを使った営業日
from pandas.tseries.offsets import CustomBusinessDay

jpn_bd = CustomBusinessDay(calendar=JapaneseHolidayCalendar())
today = pd.Timestamp(2024, 12, 20)
result = today + 5 * jpn_bd
print(result)

ただし、日本の祝日は「春分の日」や「秋分の日」のように天文計算で決まるもの、「ハッピーマンデー」で移動するものがあり、手動での定義は現実的ではありません。

jpholiday ライブラリ

日本の祝日に特化した jpholiday ライブラリを使うと、複雑な祝日ルールを自分で実装する必要がなくなります。

import jpholiday
from datetime import date

# 特定の日が祝日かどうか
print(jpholiday.is_holiday(date(2024, 11, 3)))
# True(文化の日)

# 祝日名を取得
print(jpholiday.is_holiday_name(date(2024, 11, 3)))
# 文化の日

# 期間内の祝日一覧
holidays = jpholiday.between(date(2024, 1, 1), date(2024, 12, 31))
for d, name in holidays:
    print(f"{d}: {name}")

jpholiday は振替休日や国民の休日も正しく計算してくれます。

numpy.busday

高速だが祝日リストを自分で用意する必要がある

jpholiday

日本の祝日を自動計算してくれるが、営業日計算機能自体はない

営業日計算の実装

jpholiday と組み合わせて営業日計算を実装してみます。

import jpholiday
from datetime import date, timedelta

def is_business_day(d: date) -> bool:
    """営業日かどうか判定"""
    # 土日チェック
    if d.weekday() >= 5:
        return False
    # 祝日チェック
    if jpholiday.is_holiday(d):
        return False
    return True

def add_business_days(start: date, days: int) -> date:
    """営業日を加算"""
    current = start
    remaining = days
    direction = 1 if days >= 0 else -1
    remaining = abs(remaining)
    
    while remaining > 0:
        current += timedelta(days=direction)
        if is_business_day(current):
            remaining -= 1
    
    return current

# 使用例
today = date(2024, 12, 20)
result = add_business_days(today, 5)
print(result)

この実装はシンプルですが、大量の日付を処理する場合はパフォーマンスに問題が出ます。

高速化のアプローチ

営業日を事前計算してキャッシュする方法が効果的です。

import jpholiday
from datetime import date, timedelta
from functools import lru_cache

@lru_cache(maxsize=None)
def get_business_days_list(year: int) -> list[date]:
    """年間の営業日リストを生成"""
    start = date(year, 1, 1)
    end = date(year, 12, 31)
    
    business_days = []
    current = start
    while current <= end:
        if current.weekday() < 5 and not jpholiday.is_holiday(current):
            business_days.append(current)
        current += timedelta(days=1)
    
    return business_days

def add_business_days_fast(start: date, days: int) -> date:
    """キャッシュを使った高速営業日計算"""
    bd_list = get_business_days_list(start.year)
    
    try:
        idx = bd_list.index(start)
    except ValueError:
        # startが営業日でない場合、次の営業日を探す
        for i, d in enumerate(bd_list):
            if d > start:
                idx = i
                break
    
    new_idx = idx + days
    
    # 年をまたぐ場合の処理
    while new_idx >= len(bd_list):
        new_idx -= len(bd_list)
        bd_list = get_business_days_list(bd_list[0].year + 1)
    
    return bd_list[new_idx]

月末営業日の計算

「月末の最終営業日」もよく使う計算パターンです。

import jpholiday
from datetime import date, timedelta
import calendar

def last_business_day_of_month(year: int, month: int) -> date:
    """月の最終営業日を取得"""
    # 月末日を取得
    last_day = calendar.monthrange(year, month)[1]
    d = date(year, month, last_day)
    
    # 営業日になるまで遡る
    while d.weekday() >= 5 or jpholiday.is_holiday(d):
        d -= timedelta(days=1)
    
    return d

# 使用例
for month in range(1, 13):
    last_bd = last_business_day_of_month(2024, month)
    print(f"2024年{month}月の最終営業日: {last_bd}")

会社独自の休業日

実務では会社独自の休業日(創立記念日、年末年始の特別休暇など)を考慮する必要があります。

import jpholiday
from datetime import date

class BusinessDayCalculator:
    def __init__(self, company_holidays: list[date] = None):
        self.company_holidays = set(company_holidays or [])
    
    def is_business_day(self, d: date) -> bool:
        if d.weekday() >= 5:
            return False
        if jpholiday.is_holiday(d):
            return False
        if d in self.company_holidays:
            return False
        return True

# 使用例
company_holidays = [
    date(2024, 12, 28),  # 仕事納め翌日
    date(2024, 12, 30),
    date(2024, 12, 31),
]

calc = BusinessDayCalculator(company_holidays)
print(calc.is_business_day(date(2024, 12, 30)))
# False(会社休業日)
NumPy を使う場合

高速だが祝日リストを手動管理。バッチ処理向き。

jpholiday を使う場合

日本の祝日を自動計算。会社独自の休業日と組み合わせて使う。

営業日計算は一見単純ですが、祝日の扱い、年またぎ、うるう年など考慮すべき点が多いです。信頼性のあるライブラリを活用し、テストケースを充実させることが重要です。