ebuild_rasp2/ebuild/core/sunholiday.py

192 lines
6.5 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# -*- 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())