import os, datetime, math, threading, json
import customtkinter as ctk
from tkinter import messagebox
import ephem
BASE_DIR = os.path.dirname(os.path.abspath(__file__))
# =========================================================================
# ---> PENTING: SILAKAN COPAS HIJRI_DB LENGKAP DARI KODE MASTER ANDA <---
# Pastikan data indeks 9 (Bulan ke-10 / Syawal) tersedia.
# =========================================================================
HIJRI_DB = {
1447: [["Muharam", "", "", 30], ["Safar", "", "", 29], ["Rabiulawal", "", "", 30], ["Rabiulakhir", "", "", 30], ["Jumadilawal", "", "", 29], ["Jumadilakhir", "", "", 30], ["Rajab", "", "", 30], ["Syakban", "", "", 29], ["Ramadan", "Rabu Legi", "18-Feb-2026", 30], ["Syawal", "Jumat Legi", "20-Mar-2026", 29], ["Zulkaidah", "", "", 30], ["Zulhijah", "", "", 29]],
1448: [["Muharam", "", "", 30], ["Safar", "", "", 29], ["Rabiulawal", "", "", 30], ["Rabiulakhir", "", "", 30], ["Jumadilawal", "", "", 29], ["Jumadilakhir", "", "", 30], ["Rajab", "", "", 30], ["Syakban", "", "", 29], ["Ramadan", "Senin", "08-Feb-2027", 29], ["Syawal", "Selasa", "09-Mar-2027", 30], ["Zulkaidah", "", "", 30], ["Zulhijah", "", "", 29]],
# ... Tambahkan s/d 1496 H
}
# Auto-load dari file JSON jika ada
try:
DB_JSON_PATH = os.path.join(BASE_DIR, "db_hijriah.json")
if os.path.exists(DB_JSON_PATH):
with open(DB_JSON_PATH, "r", encoding="utf-8") as f:
HIJRI_DB.update({int(k): v for k, v in json.load(f).items()})
except Exception: pass
class Menu21App(ctk.CTk):
def __init__(self):
super().__init__()
self.title("Komparasi 50 Tahun Syawal (Modul 21)")
self.geometry("1100x650")
ctk.set_appearance_mode("Dark")
self.setup_ui()
def get_header(self, width):
return "\n".join(line.center(width) for line in ["By the Name of Allah", "KALENDER HIJRIAH GLOBAL TUNGGAL", "KHGT Times 7.2 - Komparasi Syawal"])
def setup_ui(self):
self.sidebar = ctk.CTkFrame(self, width=250)
self.sidebar.pack(side="left", fill="y", padx=10, pady=10)
ctk.CTkLabel(self.sidebar, text="KOMPARASI 50 TAHUN\n(SYAWAL)", font=("Segoe UI", 16, "bold"), text_color="#00E5FF").pack(pady=20)
ctk.CTkLabel(self.sidebar, text="Rentang: 1447 H - 1496 H", text_color="yellow").pack(pady=5)
self.btn_hitung = ctk.CTkButton(self.sidebar, text="▶ MULAI ANALISIS", font=("Segoe UI", 12, "bold"), command=self.analisis_komparasi_syawal, height=45)
self.btn_hitung.pack(pady=20, fill="x", padx=20)
self.lbl_status = ctk.CTkLabel(self.sidebar, text="Sistem Siap", text_color="#00E676")
self.lbl_status.pack()
self.textbox = ctk.CTkTextbox(self, font=("Consolas", 13), wrap="none")
self.textbox.pack(side="right", fill="both", expand=True, padx=10, pady=10)
self.textbox.insert("1.0", "Klik '▶ MULAI ANALISIS' untuk membandingkan jatuhnya 1 Syawal antara KHGT dan MABIMS Sabang.")
self.textbox.configure(state="disabled")
def analisis_komparasi_syawal(self):
threading.Thread(target=self._proses_komparasi_syawal, daemon=True).start()
def _proses_komparasi_syawal(self):
self.after(0, lambda: self.lbl_status.configure(text="Menganalisis 50 Tahun Syawal...", text_color="#FFAB40"))
self.after(0, lambda: self.btn_hitung.configure(state="disabled"))
self.after(0, lambda: self.textbox.configure(state="normal"))
self.after(0, lambda: self.textbox.delete("1.0", "end"))
output_lines = [
self.get_header(135),
"[ REKAPITULASI KOMPARASI AWAL SYAWAL / IDUL FITRI (1447 H - 1496 H) ]".center(135),
"KHGT (Global Alt>=5°, Eln>=8°) vs Neo MABIMS (Lokal Sabang Alt>=3°, Eln>=6.4°)".center(135),
"=" * 135,
f"{'Tahun':<8} | {'Waktu Ijtimak (UTC)':<19} | {'1 Syawal (KHGT)':<20} | {'1 Syawal (MABIMS Sabang)':<28} | {'Status / Selisih'}",
"-" * 135
]
sabang = ephem.Observer()
sabang.lat, sabang.lon = math.radians(5.8942), math.radians(95.3184)
sabang.elevation, sabang.pressure, sabang.temp = 0, 1010, 25
matahari, bulan = ephem.Sun(), ephem.Moon()
bulan_map = {"Jan":1, "Feb":2, "Mar":3, "Apr":4, "May":5, "Jun":6, "Jul":7, "Aug":8, "Sep":9, "Oct":10, "Nov":11, "Dec":12}
for thn_h in range(1447, 1497):
try:
if thn_h not in HIJRI_DB:
output_lines.append(f"{thn_h} H | [DATA KOSONG] Database HIJRI_DB tahun ini tidak ditemukan.")
continue
# Index 9 adalah bulan ke-10 (Syawal)
tgl_khgt_str = HIJRI_DB[thn_h][9][2]
parts = tgl_khgt_str.split('-')
dt_khgt = datetime.datetime(int(parts[2]), bulan_map.get(parts[1], 1), int(parts[0]))
# Tanggal Rukyat (29 Ramadhan) = H-1 dari 1 Syawal KHGT
dt_rukyat = dt_khgt - datetime.timedelta(days=1)
ijtimak = ephem.previous_new_moon(ephem.Date(dt_rukyat) + 5)
str_ijtimak = ijtimak.datetime().strftime("%d-%m-%Y %H:%M")
sabang.date = ephem.Date(dt_rukyat.replace(hour=0, minute=0, second=0))
try: waktu_sunset = sabang.next_setting(matahari)
except: waktu_sunset = ephem.Date(dt_rukyat.replace(hour=11, minute=30, second=0))
sabang.date = waktu_sunset
matahari.compute(sabang)
bulan.compute(sabang)
alt_topo = math.degrees(bulan.alt)
elong_topo = math.degrees(ephem.separation(matahari, bulan))
umur_bulan = waktu_sunset - ijtimak
if umur_bulan > 0 and alt_topo >= 3.0 and elong_topo >= 6.4:
dt_mabims = dt_khgt
status = "Serentak (Idul Fitri Sama)"
else:
dt_mabims = dt_khgt + datetime.timedelta(days=1)
status = "Beda (MABIMS Istikmal 30 Hr)"
str_khgt = dt_khgt.strftime("%d %b %Y")
str_mabims = dt_mabims.strftime("%d %b %Y")
output_lines.append(f"{thn_h} H | {str_ijtimak:<19} | {str_khgt:<20} | {str_mabims:<28} | {status}")
if (thn_h - 1446) % 10 == 0 and thn_h != 1496:
output_lines.append("-" * 135)
except Exception as e:
output_lines.append(f"{thn_h} H | Error: {str(e)}")
output_lines.append("=" * 135)
self.after(0, lambda: self.textbox.insert("1.0", "\n".join(output_lines)))
self.after(0, lambda: self.textbox.configure(state="disabled"))
self.after(0, lambda: self.lbl_status.configure(text="Komparasi Syawal Selesai", text_color="#00E676"))
self.after(0, lambda: self.btn_hitung.configure(state="normal"))
if __name__ == "__main__":
app = Menu21App()
app.mainloop()