a4f8620a71
## 新增模块 (16个) ### P0 精度修复 - ashtakavarga: calc_prastara_av() + calc_sodhita_av() - kakshya.py: Kakshya评分系统 (8区间×3.75°) - shadbala.py: Sputa Drishti + Yuddha Bala ### P1 核心升级 - bhava_bala.py: 宫位三元力量 (jyotishganit MIT) - pancha_mahapurusha.py: PMC完整检测含4层失效条件 - sade_sati.py: Sade Sati+Kantaka Shani - sudarshana_chakra.py: 三参考点盘+收敛分析 - tajika.py: Sahams 7→36 + Tajika Yogas 10种 - birth_time_rectifier.py: 生时矫正 ### P2 覆盖扩展 - kp_system.py: KP Sublord+ABCD Significator (diliprk/VedicAstro MIT) - synastry.py: 16因子合盘36分制 (dashaflow MIT) - muhurtha_election.py: 6活动选举 (dashaflow MIT) - career_analysis.py: 结构化事业引擎 - relationship_analysis.py: 结构化感情引擎 - conditional_dashas.py: Dwisaptati+Shattrimsa+Dwadashottari - divisional_charts_extended: D81/D108/D144 - remedies.py: 5类补救系统 ## 修改文件 jaimini/dasha_calculator/shadbala/SKILL.md/COVERAGE_AUDIT等12个 ## 开源复用: 4个MIT项目
162 lines
5.2 KiB
Python
162 lines
5.2 KiB
Python
import pytz
|
|
from timezonefinder import TimezoneFinder
|
|
from datetime import datetime, date, timedelta
|
|
from dateutil.relativedelta import relativedelta
|
|
|
|
##
|
|
def clean_select_objects_split_str(input_str):
|
|
"""Rename and Clean certain chart objects like North, South Node and Fortuna"""
|
|
cleaned_str = (input_str.strip('<').strip('>')
|
|
.replace("North Node", "Rahu")
|
|
.replace("South Node", "Ketu")
|
|
.replace("Pars Fortuna", "Fortuna"))
|
|
return cleaned_str.split()
|
|
|
|
def utc_offset_str_to_float(utc_offset: str) -> float:
|
|
hours, minutes = map(int, utc_offset.split(':'))
|
|
return hours + minutes / 60.0 if utc_offset.startswith('+') else -1 * (abs(hours) + minutes / 60.0)
|
|
|
|
|
|
def pretty_data_table(named_tuple_data : list):
|
|
"""Converts a list of NamedTuple Collections to a PrettyTable"""
|
|
from prettytable import PrettyTable
|
|
# Create a PrettyTable instance
|
|
table = PrettyTable()
|
|
|
|
# Add field names (column headers)
|
|
table.field_names = named_tuple_data[0]._fields
|
|
|
|
# Add rows
|
|
for data in named_tuple_data:
|
|
table.add_row(data)
|
|
|
|
return table
|
|
|
|
def dms_to_decdeg(dms_str: str):
|
|
"""
|
|
This function converts a string input in Degrees:Mins:Secs to Decimal Degrees
|
|
"""
|
|
dms = dms_str.split(':')
|
|
degrees = float(dms[0])
|
|
minutes = float(dms[1])
|
|
seconds = float(dms[2])
|
|
return round(degrees + (minutes/60) + (seconds/3600), 4)
|
|
|
|
|
|
def dms_to_mins(dms_str: str):
|
|
"""
|
|
This function converts a string input in Degrees:Mins:Secs to total minutes.
|
|
"""
|
|
dms = dms_str.split(':')
|
|
degrees = int(dms[0])
|
|
minutes = int(dms[1])
|
|
seconds = int(dms[2])
|
|
total_minutes = degrees * 60 + minutes + seconds / 60
|
|
return round(total_minutes, 2)
|
|
|
|
def dms_difference(dms1_str: str, dms2_str: str):
|
|
"""
|
|
This function computes the difference between two degree:mins:secs string objects
|
|
and returns the difference as a degree:mins:secs string.
|
|
"""
|
|
def dms_to_seconds(dms_str):
|
|
dms = dms_str.split(':')
|
|
degrees = int(dms[0])
|
|
minutes = int(dms[1])
|
|
seconds = int(dms[2])
|
|
total_seconds = degrees * 3600 + minutes * 60 + seconds
|
|
return total_seconds
|
|
|
|
def seconds_to_dms(seconds):
|
|
degrees = seconds // 3600
|
|
seconds %= 3600
|
|
minutes = seconds // 60
|
|
seconds %= 60
|
|
return f"{int(degrees)}:{int(minutes)}:{int(seconds)}"
|
|
|
|
dms1_seconds = dms_to_seconds(dms1_str)
|
|
dms2_seconds = dms_to_seconds(dms2_str)
|
|
|
|
diff_seconds = abs(dms1_seconds - dms2_seconds)
|
|
|
|
return seconds_to_dms(diff_seconds)
|
|
|
|
|
|
def convert_years_ymdhm(years):
|
|
"""
|
|
This function converts decimal years into years, months, days, hours, and minutes.
|
|
"""
|
|
# Constants
|
|
months_per_year = 12
|
|
days_per_month = 30 # Approximation
|
|
hours_per_day = 24
|
|
minutes_per_hour = 60
|
|
|
|
# Compute the breakdown
|
|
whole_years = int(years)
|
|
months = (years - whole_years) * months_per_year
|
|
whole_months = int(months)
|
|
days = (months - whole_months) * days_per_month
|
|
whole_days = int(days)
|
|
hours = (days - whole_days) * hours_per_day
|
|
whole_hours = int(hours)
|
|
minutes = (hours - whole_hours) * minutes_per_hour
|
|
whole_minutes = int(minutes)
|
|
|
|
return whole_years, whole_months, whole_days, whole_hours, whole_minutes
|
|
|
|
def compute_new_date(start_date : tuple, diff_value : float, direction: str):
|
|
"""
|
|
This function computes a new date and time given an initial date and time and a time difference.
|
|
"""
|
|
# Unpack start_date and diff_params
|
|
year, month, day, hour, minute = start_date
|
|
years, months, days, hours, minutes = convert_years_ymdhm(diff_value)
|
|
|
|
# Create initial datetime object
|
|
initial_date = datetime(year, month, day, hour, minute)
|
|
|
|
# Compute relativedelta object
|
|
time_difference = relativedelta(years=years, months=months, days=days, hours=hours, minutes=minutes)
|
|
|
|
# Compute new date
|
|
if direction == 'backward':
|
|
new_date = initial_date - time_difference
|
|
elif direction == 'forward':
|
|
new_date = initial_date + time_difference
|
|
else:
|
|
raise ValueError("direction must be either 'backward' or 'forward'")
|
|
|
|
return new_date
|
|
|
|
def get_utc_offset(timezone_loc : str, date: datetime):
|
|
"""
|
|
Returns the UTC offset as a timedelta for a given latitude, longitude, and date.
|
|
|
|
Parameters:
|
|
- timezone_loc (str) : The timezone location to compute tz info (Eg: America/New_York)
|
|
- date (datetime): The date for which to find the UTC offset.
|
|
|
|
Returns:
|
|
- timedelta: UTC offset as a timedelta object.
|
|
"""
|
|
# Get the timezone object
|
|
timezone = pytz.timezone(timezone_loc)
|
|
|
|
# Localize the date to the timezone
|
|
localized_date = timezone.localize(date)
|
|
|
|
# Get the UTC offset in seconds
|
|
utc_offset_sec = localized_date.utcoffset().total_seconds()
|
|
hours, remainder = divmod(abs(utc_offset_sec), 3600)
|
|
minutes = remainder // 60
|
|
|
|
# Format the offset as a string
|
|
sign = "+" if utc_offset_sec >= 0 else "-"
|
|
utc_offset_str = f"{sign}{int(hours):02}:{int(minutes):02}"
|
|
|
|
# Convert seconds to a timedelta
|
|
utc_offset = timedelta(seconds=utc_offset_sec)
|
|
|
|
|
|
return utc_offset_str, utc_offset |