# -*- coding: utf-8 -*- from __future__ import annotations __title__ = "sunholiday" __author__ = 'Mehmet Karatay & "Saraswati" (ChatGPT)' __purpose__ = "Astral ve eholidays_tr kullanarak güneş / tatil / mevsim bilgisi üretir" __version__ = "0.1.1" __date__ = "2025-11-22" """ ebuild/core/sunholiday.py Revision : 2025-11-22 Authors : Mehmet Karatay & "Saraswati" (ChatGPT) Amaç ----- Eski sistemde kullandığın SunHolidayInfo sınıfını, ebuild projesi için bağımsız bir modüle taşıdık. Bu modül: - Astral ile gün doğumu / gün batımı / öğlen - eholidays_tr ile resmi tatil (yoksa graceful fallback) - Basit mevsim hesabı bilgilerini üretir ve SeasonController tarafından kullanılır. Dış arayüz: class SunHolidayInfo: - get_info() -> dict - print_info() - to_json() """ import json from datetime import datetime from enum import Enum from astral import LocationInfo from astral.sun import sun import pytz # eholidays_tr yoksa sistem göçmesin → dummy tracker try: from eholidays_tr import HolidayTracker # type: ignore except Exception: class HolidayTracker: # type: ignore def __init__(self, year: int) -> None: self.year = year def is_holiday(self, dt) -> None: return None class Season(Enum): KIS = "Kış" ILKBAHAR = "İlkbahar" YAZ = "Yaz" SONBAHAR = "Sonbahar" class SunHolidayInfo: """ Astral + eholidays_tr kombinasyonu ile gün / tatil / mevsim bilgisi üretir. """ def __init__( self, current_datetime=None, city_name: str = "Ankara", country: str = "Turkey", timezone: str = "Europe/Istanbul", latitude: float = 39.92077, longitude: float = 32.85411, ) -> None: self.city = city_name self.country = country self.timezone_str = timezone self.timezone = pytz.timezone(timezone) self.lat = latitude self.lon = longitude if current_datetime is None: self.current_datetime = datetime.now(self.timezone) else: # Eğer naive datetime geldiyse timezone ekleyelim if current_datetime.tzinfo is None: self.current_datetime = self.timezone.localize(current_datetime) else: self.current_datetime = current_datetime.astimezone(self.timezone) self.location = LocationInfo( self.city, self.country, self.timezone_str, self.lat, self.lon ) self.work_date = self.current_datetime # --------------------------------------------------------- # Yardımcılar # --------------------------------------------------------- def return_init(self) -> str: return ( f"SunHolidayInfo: {self.country} {self.city} " f"{self.timezone_str} {self.lat} - {self.lon}" ) def get_season(self, date_obj: datetime): """ Astronomik mevsim aralıklarıyla kaba mevsim ve gün bilgisi üretir. """ ranges = { Season.KIS: [ (date_obj.replace(month=1, day=1), date_obj.replace(month=3, day=20)), (date_obj.replace(month=12, day=21), date_obj.replace(month=12, day=31)), ], Season.ILKBAHAR: [ (date_obj.replace(month=3, day=21), date_obj.replace(month=6, day=20)) ], Season.YAZ: [ (date_obj.replace(month=6, day=21), date_obj.replace(month=9, day=22)) ], Season.SONBAHAR: [ (date_obj.replace(month=9, day=23), date_obj.replace(month=12, day=20)) ], } for season, periods in ranges.items(): for start, end in periods: if start <= date_obj <= end: total_days = (end - start).days + 1 passed_days = (date_obj - start).days remaining_days = (end - date_obj).days return { "season": season.value, "season_start": start.isoformat(), "season_end": end.isoformat(), "season_day": total_days, "season_passed": passed_days, "season_remaining": remaining_days, } return None # --------------------------------------------------------- # Ana API # --------------------------------------------------------- def get_info(self) -> dict: """ Astral + HolidayTracker + mevsim hesabını bir dict olarak döner. """ sun_data = sun( self.location.observer, date=self.work_date, tzinfo=self.timezone, ) tracker = HolidayTracker(self.work_date.year) holiday_label = tracker.is_holiday(self.work_date) season_info = self.get_season(self.work_date) return { "date": self.work_date.isoformat(), "sunrise": sun_data["sunrise"].strftime("%H:%M:%S"), "sunset": sun_data["sunset"].strftime("%H:%M:%S"), "noon": sun_data["noon"].strftime("%H:%M:%S"), "is_holiday": bool(holiday_label), "holiday_label": holiday_label if holiday_label else "Yok", "season": season_info["season"] if season_info else None, "season_start": season_info["season_start"] if season_info else None, "season_end": season_info["season_end"] if season_info else None, "season_day": season_info["season_day"] if season_info else None, "season_passed": season_info["season_passed"] if season_info else None, "season_remaining": season_info["season_remaining"] if season_info else None, } def print_info(self) -> None: info = self.get_info() print(f"Güneş bilgileri - {self.location.name}, {info['date']}") print(f"Doğuş: {info['sunrise']}") print(f"Batış: {info['sunset']}") print(f"Öğlen: {info['noon']}") print(f"Tatil mi?: {'Evet' if info['is_holiday'] else 'Hayır'}") if info["is_holiday"]: print(f"Etiket: {info['holiday_label']}") def to_json(self) -> str: return json.dumps(self.get_info(), ensure_ascii=False, indent=2) if __name__ == "__main__": s = SunHolidayInfo() print(s.return_init()) print(s.to_json())