File size: 6,083 Bytes
4d0ffdd
 
 
 
 
 
 
 
 
6a28f91
4d0ffdd
f6c65ef
4d0ffdd
 
 
 
 
f6c65ef
4d0ffdd
 
 
 
f6c65ef
4d0ffdd
 
f6c65ef
4d0ffdd
 
 
 
 
f6c65ef
4d0ffdd
 
f6c65ef
4d0ffdd
 
 
 
f6c65ef
4d0ffdd
 
f6c65ef
4d0ffdd
 
 
 
f6c65ef
4d0ffdd
 
f6c65ef
4d0ffdd
 
f6c65ef
4d0ffdd
 
 
 
 
 
f6c65ef
4d0ffdd
 
f6c65ef
4d0ffdd
f6c65ef
4d0ffdd
 
f6c65ef
4d0ffdd
 
 
f6c65ef
4d0ffdd
 
 
 
 
f6c65ef
4d0ffdd
 
 
 
f6c65ef
4d0ffdd
f6c65ef
4d0ffdd
 
f6c65ef
4d0ffdd
 
 
f6c65ef
4d0ffdd
 
 
 
 
f6c65ef
4d0ffdd
 
f6c65ef
4d0ffdd
 
 
 
f6c65ef
4d0ffdd
f6c65ef
4d0ffdd
 
f6c65ef
4d0ffdd
 
 
f6c65ef
4d0ffdd
 
 
 
 
f6c65ef
4d0ffdd
 
 
 
f6c65ef
4d0ffdd
 
f6c65ef
4d0ffdd
 
 
 
f6c65ef
4d0ffdd
f6c65ef
4d0ffdd
 
f6c65ef
4d0ffdd
 
f6c65ef
4d0ffdd
 
 
 
f6c65ef
4d0ffdd
 
f6c65ef
4d0ffdd
f6c65ef
4d0ffdd
 
f6c65ef
4d0ffdd
 
f6c65ef
4d0ffdd
 
 
 
f6c65ef
4d0ffdd
 
f6c65ef
4d0ffdd
 
 
f6c65ef
4d0ffdd
 
 
 
 
f6c65ef
4d0ffdd
 
f6c65ef
4d0ffdd
 
 
f6c65ef
4d0ffdd
 
 
 
 
f6c65ef
4d0ffdd
 
 
 
f6c65ef
4d0ffdd
f6c65ef
4d0ffdd
 
f6c65ef
4d0ffdd
f6c65ef
4d0ffdd
 
 
 
 
f6c65ef
 
 
4d0ffdd
 
f6c65ef
4d0ffdd
f6c65ef
4d0ffdd
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
"""Court calendar utilities with working days and seasonality.

This module provides utilities for calculating working days considering
court holidays, seasonality, and Karnataka High Court calendar.
"""

from datetime import date, timedelta
from typing import List, Set

from src.data.config import (
    SEASONALITY_FACTORS,
    WORKING_DAYS_PER_YEAR,
)


class CourtCalendar:
    """Manages court working days and seasonality.

    Attributes:
        holidays: Set of holiday dates
        working_days_per_year: Expected working days annually
    """

    def __init__(self, working_days_per_year: int = WORKING_DAYS_PER_YEAR):
        """Initialize court calendar.

        Args:
            working_days_per_year: Annual working days (default 192)
        """
        self.working_days_per_year = working_days_per_year
        self.holidays: Set[date] = set()

    def add_holiday(self, holiday_date: date) -> None:
        """Add a holiday to the calendar.

        Args:
            holiday_date: Date to mark as holiday
        """
        self.holidays.add(holiday_date)

    def add_holidays(self, holiday_dates: List[date]) -> None:
        """Add multiple holidays.

        Args:
            holiday_dates: List of dates to mark as holidays
        """
        self.holidays.update(holiday_dates)

    def is_working_day(self, check_date: date) -> bool:
        """Check if a date is a working day.

        Args:
            check_date: Date to check

        Returns:
            True if date is a working day (not weekend or holiday)
        """
        # Saturday (5) and Sunday (6) are weekends
        if check_date.weekday() in (5, 6):
            return False

        if check_date in self.holidays:
            return False

        return True

    def next_working_day(self, start_date: date, days_ahead: int = 1) -> date:
        """Get the next working day after a given number of working days.

        Args:
            start_date: Starting date
            days_ahead: Number of working days to advance

        Returns:
            Next working day date
        """
        current = start_date
        working_days_found = 0

        while working_days_found < days_ahead:
            current += timedelta(days=1)
            if self.is_working_day(current):
                working_days_found += 1

        return current

    def working_days_between(self, start_date: date, end_date: date) -> int:
        """Count working days between two dates (inclusive).

        Args:
            start_date: Start of range
            end_date: End of range

        Returns:
            Number of working days
        """
        if start_date > end_date:
            return 0

        count = 0
        current = start_date

        while current <= end_date:
            if self.is_working_day(current):
                count += 1
            current += timedelta(days=1)

        return count

    def get_working_days_in_month(self, year: int, month: int) -> List[date]:
        """Get all working days in a specific month.

        Args:
            year: Year
            month: Month (1-12)

        Returns:
            List of working day dates
        """
        # Get first and last day of month
        first_day = date(year, month, 1)

        if month == 12:
            last_day = date(year, 12, 31)
        else:
            last_day = date(year, month + 1, 1) - timedelta(days=1)

        working_days = []
        current = first_day

        while current <= last_day:
            if self.is_working_day(current):
                working_days.append(current)
            current += timedelta(days=1)

        return working_days

    def get_working_days_in_year(self, year: int) -> List[date]:
        """Get all working days in a year.

        Args:
            year: Year

        Returns:
            List of working day dates
        """
        working_days = []

        for month in range(1, 13):
            working_days.extend(self.get_working_days_in_month(year, month))

        return working_days

    def get_seasonality_factor(self, check_date: date) -> float:
        """Get seasonality factor for a date based on month.

        Args:
            check_date: Date to check

        Returns:
            Seasonality multiplier (from config)
        """
        return SEASONALITY_FACTORS.get(check_date.month, 1.0)

    def get_expected_capacity(self, check_date: date, base_capacity: int) -> int:
        """Get expected capacity adjusted for seasonality.

        Args:
            check_date: Date to check
            base_capacity: Base daily capacity

        Returns:
            Adjusted capacity
        """
        factor = self.get_seasonality_factor(check_date)
        return int(base_capacity * factor)

    def generate_court_calendar(self, start_date: date, end_date: date) -> List[date]:
        """Generate list of all court working days in a date range.

        Args:
            start_date: Start of simulation
            end_date: End of simulation

        Returns:
            List of working day dates
        """
        working_days = []
        current = start_date

        while current <= end_date:
            if self.is_working_day(current):
                working_days.append(current)
            current += timedelta(days=1)

        return working_days

    def add_standard_holidays(self, year: int) -> None:
        """Add standard Indian national holidays for a year.

        This is a simplified set. In production, use actual court holiday calendar.

        Args:
            year: Year to add holidays for
        """
        # Standard national holidays (simplified)
        holidays = [
            date(year, 1, 26),  # Republic Day
            date(year, 8, 15),  # Independence Day
            date(year, 10, 2),  # Gandhi Jayanti
            date(year, 12, 25),  # Christmas
        ]

        self.add_holidays(holidays)

    def __repr__(self) -> str:
        return f"CourtCalendar(working_days/year={self.working_days_per_year}, holidays={len(self.holidays)})"