import re from datetime import datetime, timedelta import holidays import calendar import json def timedelta_to_string(td: timedelta) -> str: """Convert a timedelta object to a string in the format HH:MM.""" total_minutes = int(td.total_seconds() / 60) hours = abs(total_minutes) // 60 minutes = abs(total_minutes) % 60 sign = "-" if td.total_seconds() < 0 else "" return f"{sign}{hours:02}:{minutes:02}" def process_input_txt(text: str) -> list: """ Process text containing work records and return a sorted list of dictionaries containing the extracted data. Args: text (str): Text containing work records. Returns: list[dict]: List of dictionaries containing the fields 'enter', 'exit', and 'duration'. """ pattern = re.compile( r""" (?P\S+\s\S+)\s+ # Name (?P\d{2}\.\d{2}\.\d{4}\s\d{2}:\d{2}:\d{2})\s+ # Start date (?P\d{2}\.\d{2}\.\d{4}\s\d{2}:\d{2}:\d{2})\s+ # End date (?P\d{2}:\d{2}) # Duration """, re.VERBOSE, ) results = [] for line in text.splitlines(): line = line.strip() if not line: continue match = pattern.match(line) if match: try: start_date = datetime.strptime(match.group("start_date"), "%d.%m.%Y %H:%M:%S") end_date = datetime.strptime(match.group("end_date"), "%d.%m.%Y %H:%M:%S") duration = timedelta( hours=int(match.group("duration")[:2]), minutes=int(match.group("duration")[3:]) ) results.append( { "enter": start_date, "exit": end_date, "duration": duration, } ) except ValueError: # Ignore invalid dates continue # Sort results by start date results.sort(key=lambda x: x["enter"]) return results def generate_monthly_summary(work_records: list, year: int, month: int) -> list: # Polska lista dni świątecznych pl_holidays = holidays.Poland(years=year) # Liczba dni w miesiącu _, num_days = calendar.monthrange(year, month) summary = [] # Oblicz godziny pracy na dzień (8h 15min = 8.25h) daily_work_hours = timedelta(hours=8, minutes=15) holiday_work_hours = timedelta(hours=0, minutes=15) # Suma godzin oczekiwanych i rzeczywistych total_expected = timedelta(0) total_actual = timedelta(0) # Tworzenie wpisów dla każdego dnia for day in range(1, num_days + 1): date = datetime(year, month, day) weekday = date.weekday() # 0 = poniedziałek, ..., 6 = niedziela is_holiday = date in pl_holidays should_work = weekday < 5 and not is_holiday # Praca w dni robocze poza świętami # Aktualizuj oczekiwany czas pracy if should_work: total_expected += daily_work_hours # Znajdź godziny faktyczne dla tego dnia daily_actual = sum( (record["duration"] for record in work_records if record["enter"].date() == date.date()) , timedelta() ) total_actual += daily_actual # Dodanie timedelta do sumy # Dodaj dane do listy podsumowania summary.append({ "day": date.date(), "weekday": weekday, "is_holiday": is_holiday, "total_expected": timedelta_to_string(total_expected), "total_actual": timedelta_to_string(total_actual), "total_diffrance": timedelta_to_string(total_actual - total_expected), "daily_actual": timedelta_to_string(daily_actual), "daily_diffrance": timedelta_to_string(daily_actual - (daily_work_hours if should_work else holiday_work_hours if daily_actual >= holiday_work_hours else timedelta(0))), }) return summary # text3 = """ # Worked hours # Attendance Reason # Marcin Nowak 22.11.2024 07:12:30 22.11.2024 16:05:33 08:53 # Marcin Nowak 21.11.2024 07:25:38 21.11.2024 16:43:19 09:18 # Marcin Nowak 20.11.2024 07:31:46 20.11.2024 15:47:36 08:16 # Marcin Nowak 19.11.2024 07:10:39 19.11.2024 15:54:14 08:44 # Marcin Nowak 18.11.2024 07:13:11 18.11.2024 16:04:15 08:51 # Marcin Nowak 15.11.2024 07:06:31 15.11.2024 15:41:49 08:35 # Marcin Nowak 14.11.2024 06:56:23 14.11.2024 16:11:52 09:15 # Marcin Nowak 13.11.2024 07:12:25 13.11.2024 17:19:58 10:08 # Marcin Nowak 12.11.2024 07:40:57 12.11.2024 16:10:42 08:30 # Marcin Nowak 08.11.2024 07:01:22 08.11.2024 15:48:01 08:47 # Marcin Nowak 07.11.2024 07:07:53 07.11.2024 16:26:30 09:19 # Marcin Nowak 06.11.2024 07:11:46 06.11.2024 16:08:43 08:57 # Marcin Nowak 05.11.2024 07:16:33 05.11.2024 16:10:52 08:54 # Marcin Nowak 04.11.2024 07:28:10 04.11.2024 15:51:19 08:23 # """ # # Przetwórz dane wejściowe # work_records = process_input_txt(text3) # date = work_records[-1]["enter"].date() # monthly_summary = generate_monthly_summary(work_records, date.year, date.month) # # Przykład wyświetlenia podsumowania # import pprint # pprint.pprint(monthly_summary)