import csv import hashlib from datetime import datetime, timedelta def generate_uid(full_name: str, domain: str = "mupts.local") -> str: """ Генерирует стабильный уникальный идентификатор (UID) на основе ФИО. """ if not full_name: return "" # 1. Нормализация: нижний регистр и удаление двойных пробелов clean_name = " ".join(full_name.strip().lower().split()) # 2. Хеширование: используем MD5 (он быстрый и короткий) # Берем первые 16 символов хеша — этого более чем достаточно для избежания коллизий в рамках компании name_hash = hashlib.md5(clean_name.encode('utf-8')).hexdigest()[:16] # 3. Формирование формата UID (по стандарту RFC 5545 рекомендуется формат id@domain) return f"{name_hash}@{domain}" def csv_to_ics(csv_file_path, ics_file_path): ics_content = [ "BEGIN:VCALENDAR", "VERSION:2.0", "PRODID:-//MUT_TS//Birthdays//RU", "CALSCALE:GREGORIAN" ] # with open(csv_file_path, mode='r', encoding='utf-8') as file: with open(csv_file_path, mode='r', encoding='windows-1251') as file: # Предполагаем, что разделитель - запятая. Если точка с запятой, измените на delimiter=';' reader = csv.DictReader(file, delimiter=';') for row in reader: # Извлекаем данные (замените ключи на названия ваших колонок в CSV) name = row.get('Subject', '').strip() date_str = row.get('Start Date', '').strip().rstrip('.') # убираем случайные точки на конце desckription = row.get('Description', '').strip() location = row.get('Location', '').strip() # phone = row.get('Телефон', '').strip() # address = row.get('Адрес', '').strip() if not name or not date_str: continue try: # Парсим оригинальную дату (например, 18.06.1964) start_date = datetime.strptime(date_str, "%d.%m.%Y") # Для событий на весь день дата окончания должна быть следующим днем end_date = start_date + timedelta(days=1) dtstart = start_date.strftime("%Y%m%d") dtend = end_date.strftime("%Y%m%d") # Формируем блок события ics_content.append("BEGIN:VEVENT") ics_content.append(f"UID:{generate_uid(name)}") ics_content.append(f"SUMMARY:День рождения: {name}") ics_content.append(f"DTSTART;VALUE=DATE:{dtstart}") ics_content.append(f"DTEND;VALUE=DATE:{dtend}") ics_content.append("RRULE:FREQ=YEARLY") ics_content.append(f"DESCRIPTION:{desckription}") ics_content.append(f"LOCATION:{location}") ics_content.append("TRANSP:TRANSPARENT") ics_content.append("STATUS:CONFIRMED") ics_content.append("CLASS:PUBLIC") ics_content.append("CATEGORIES:Дни рождения,МУП ТС") ics_content.append("CLASS:PUBLIC") # Первое напоминание: за 1 день (в стандартное время календаря, обычно 09:00 или 18:00 предыдущего дня) ics_content.append("BEGIN:VALARM") ics_content.append("ACTION:DISPLAY") ics_content.append("DESCRIPTION:Завтра день рождения коллеги!") ics_content.append("TRIGGER:-P1D") ics_content.append("END:VALARM") # Второе напоминание: в сам день в 07:30 (через 7 часов 30 минут после полуночи) ics_content.append("BEGIN:VALARM") ics_content.append("ACTION:DISPLAY") ics_content.append("DESCRIPTION:Сегодня день рождения!") ics_content.append("TRIGGER:PT7H30M") ics_content.append("END:VALARM") ics_content.append("END:VEVENT") except ValueError: # Пропускаем строки с некорректным форматом даты print(f"Ошибка парсинга даты для: {name} ({date_str})") continue ics_content.append("END:VCALENDAR") # Записываем всё в .ics файл with open(ics_file_path, mode='w', encoding='utf-8', newline='') as ics_file: ics_file.write("\n".join(ics_content)) # Запуск конвертации csv_to_ics('1.csv', 'birthdays.ics') print("Файл birthdays.ics успешно создан!")