python 天文库ephem 计算八字干支

import math
import ephem
from datetime import datetime, timedelta
from typing import Union

# 天干和地支的周期表
GAN10 = ["甲", "乙", "丙", "丁", "戊", "己", "庚", "辛", "壬", "癸"] #十天干
ZHI12 = ["子", "丑", "寅", "卯", "辰", "巳", "午", "未", "申", "酉", "戌", "亥"] #十二地支

# 获取当前环境的时区偏移值
def cur_time_zone_offset()->float:
    current_time = datetime.now()
    # 获取UTC时间
    utc_time = datetime.utcnow()
    # 计算小时差
    time_zone_offset = round((current_time - utc_time).seconds / 3600.0,2)
    # 以0.5为基准进行舍入操作:
    if time_zone_offset >= 0 : time_zone_offset = math.floor(time_zone_offset / 0.5 + 0.5) * 0.5
    else : time_zone_offset = math.ceil(time_zone_offset / 0.5 - 0.5) * 0.5
    return time_zone_offset



# 计算指定本地时间的真太阳时
def calculate_true_solar_time(date_local:datetime,observer_latitude:Union[str, float]=34.545811,observer_longitude:Union[str, float]=108.925825)->datetime:
    """
    根据观测者的经纬度和时间,计算真太阳时。

    参数:
    observer_latitude (str): 观测者的纬度,以度为单位。
    observer_longitude (str): 观测者的经度,以度为单位。
    date_local (datetime): 观察时间

    返回:
    datetime: 调整后的真太阳时,已考虑观测者的经纬度和时区偏移量。
    """
    # 根据观测者的经纬度和时间,计算真太阳时:
    # 计算当前时区偏移time_zone_offset
    time_zone_offset = cur_time_zone_offset()    
    # 将观测者的纬度和经度转换为ephem格式
    lat, lon = ephem.degrees(str(observer_latitude)), ephem.degrees(str(observer_longitude))

    # 创建一个新的观测者对象
    observer = ephem.Observer()
    observer.lat, observer.lon = lat, lon

    # 将输入的当地时间转换为ephem的Date格式
    date_0 = date_local - timedelta(hours=time_zone_offset)# 将本地时间转换为UTC+0时间
    utc_date = ephem.Date(date_0)

    # 设置观测者的日期和时间
    observer.date = utc_date

    # 计算太阳的位置
    sun = ephem.Sun(observer)
    # 计算本地太阳正午时间(在给定日期太阳通过当地子午线的时间)
    next_noon = observer.next_transit(sun).datetime() + timedelta(hours=time_zone_offset)
    # 计算钟表正午时间
    clock_noon = next_noon.replace(hour=12, minute=0, second=0, microsecond=0)
    # 计算太阳正午和钟表正午之间的差值
    time_diff = (clock_noon - next_noon).total_seconds() / 3600.0
    # 调整本地时间以获得真太阳时(ephem通常已经考虑光行差)
    true_solar_time = date_local + timedelta(hours=time_diff)
    return true_solar_time


# 求指定日期的年份干支(年柱)
def get_year_gan_zhi(date: datetime,observer_latitude:Union[str, float,int]=0,observer_longitude:Union[str, float,int]=0) -> str:
    startDate = datetime(2000, 2, 4, 20, 40, 24)  # 2000年立春时间
    #如果指定了站点则计算真太阳时间:
    if observer_latitude != 0 or observer_longitude != 0 : date = calculate_true_solar_time(date,observer_latitude,observer_longitude)
    diff_days = (date - startDate).days  # 计算指定日期与2000年2月4日之间的间隔天数

    # 回归年的长度:365.24218968 - 0.0000000616*(t-2000)
    day_per_year = 365.24218968 - 0.0000000616 * (diff_days / 365.24218968 / 2)  # 回归年的平均长度
    years = math.floor(diff_days / day_per_year)  #算指定日期与2000年2月4日之间的年数

    # 2000年是庚辰年
    gan_index = (years + 6) % 10  # 加6位
    zhi_index = (years + 4) % 12  # 加4位
    gan_zhi = GAN10[gan_index] + ZHI12[zhi_index]
    return gan_zhi

# 计算指定站点在特定时间的月干支(月柱)
def get_moon_gan_zhi(date: datetime,latitude:Union[str, float]=34.545811, longitude:Union[str, float]=108.925825)-> str:
    """
    计算指定站点在特定时间的月干支。

    参数:
    date : datetime
        观察时间
    latitude : float
        观察者的纬度(度)。默认为35度
    longitude : float
        观察者的经度(度)。默认为120度

    返回:
    str
        指定时间的月干支,范围从"甲子"到"癸亥"。
    """
    # 创建观察者的地球位置对象
    observer = ephem.Observer()
    observer.lat, observer.lon = ephem.degrees(str(latitude)), ephem.degrees(str(longitude))  # 纬度,经度,需要转换为弧度
    # 计算当前时区偏移hour_difference
    hour_difference = cur_time_zone_offset() 

    # 解析日期字符串
    date_local = date
    date_0 = date_local - timedelta(hours=hour_difference)# 将本地时间转换为UTC+0时间
    date = ephem.Date(date_0)
    
    # 创建观察者对象
    observer.date = date
    sun = ephem.Sun(observer)
    # 获取太阳的视黄经(转换为度):
    equ = ephem.Equatorial(sun.ra, sun.dec,epoch=date)#求太阳的视赤经视赤纬(epoch设为所求时间就是视赤经视赤纬)
    ecl_v = ephem.Ecliptic(equ)#赤经赤纬转到黄经黄纬
    solar_longitude = (float(ecl_v.lon) * 180.0 / ephem.pi) % 360.0 # 对视黄经进行修正为0到360度的范围
    
    start_date = datetime(2000, 3, 5, 14, 42, 40)  # 己卯月始于3月5日 14:42:40惊蛰
    diff_days = (date_local - start_date).days
    day_per_moon = (365.24218968 - 0.0000000616 * (diff_days / 365.24218968 / 2)) / 12
    moon_num = int(diff_days / day_per_moon)  # 从己卯月开始的第几个月
    solar_longitude_mi = (int(((solar_longitude - 15) % 360) / 30.0) + 4) % 12  # 推算月支与黄经的对应关系
    moon_num_id =  (moon_num + 3) % 12  # 月支序数
    t12_diff = (solar_longitude_mi - moon_num_id + 12) % 12 # 修正增量值(t12_diff)=精确地支序号(solar_longitude_mi)-近似地支序号(moon_num_id)
    # 修正当solar_longitude_mi和moon_num_id分别居于头尾的偏差:
    # 如果 t12_diff 大于等于 6,表示实际差值应为负数,因此再减去12
    if t12_diff >= 6:t12_diff -= 12
    moon_num += t12_diff # 月支序数修正
    gan_index = (moon_num + 5) % 10  # 加5位
    zhi_index = (moon_num + 3) % 12  # 加3位
    gan = GAN10[gan_index]  # 天干序列的获取
    zhi = ZHI12[zhi_index]   # 地支序列的获取
    return gan + zhi  # 月干支的返回



#计算日的干支(日柱)
def get_day_gan_zhi(date_local:datetime,observer_latitude:Union[str, float]=34.545811,observer_longitude:Union[str, float]=108.925825) -> str:
    start_date = datetime(1900, 1, 1, 0, 0, 0, 0) #日的分隔点是真太阳时0:0:0
    # 根据观测者的经纬度和时间,计算真太阳时(ephem通常已经考虑光行差):
    true_solar_time = calculate_true_solar_time(date_local,observer_latitude,observer_longitude)
    difference_in_days = (true_solar_time - start_date).days
	# 1900年1月1日是甲戌日:
    gan_index = (difference_in_days + 0) % 10  # 加0位
    zhi_index = (difference_in_days + 10) % 12  # 加10位
    gan_zhi = GAN10[gan_index] + ZHI12[zhi_index]
    return gan_zhi

#计算时的干支(时柱)
def get_time_gan_zhi(date_local:datetime,observer_latitude:Union[str, float]=34.545811,observer_longitude:Union[str, float]=108.925825)->str:
    """
    根据观测者的经纬度和时间,计算真太阳时。

    参数:
    observer_latitude (str): 观测者的纬度,以度为单位。
    observer_longitude (str): 观测者的经度,以度为单位。
    date_local (datetime): 观察时间

    返回:
    datetime: 调整后的真太阳时,已考虑观测者的经纬度和时区偏移量。
    """
    # 根据观测者的经纬度和时间,计算真太阳时(ephem通常已经考虑光行差):  
    true_solar_time = calculate_true_solar_time(date_local,observer_latitude,observer_longitude)
    start_time_period = datetime(1983, 12, 21, 23, 42, 15)  # 甲子月甲申日甲子时真太阳时起始点
    total_time_periods = round((true_solar_time - start_time_period).total_seconds() / 3600.0/ 2.0) # 已经过去多少个时辰
    total_time_correction = ((((true_solar_time.hour + 1) // 2 - total_time_periods) % 12) + 12) % 12 # 子时的起点是真太阳时23:00:00
    if total_time_correction >= 6:total_time_correction -= 12
    total_time_periods += total_time_correction
	# 1983-12-21 23:42:15是甲子时:
    gan_index = (total_time_periods + 0) % 10  # 加0位
    zhi_index = (total_time_periods + 0) % 12  # 加0位
    gan_zhi = GAN10[gan_index] + ZHI12[zhi_index]
    return gan_zhi


#使用示例:
date_str = '2027-12-07 0:35:30'  # 示例时间
observer_latitude, observer_longitude = '39.9', '110.8333'
date_test = datetime.strptime(date_str, '%Y-%m-%d %H:%M:%S')
moon_gan_zhi = get_moon_gan_zhi(date_test,observer_latitude,observer_longitude)
day_gan_zhi = get_day_gan_zhi(date_test,observer_latitude,observer_longitude)
year_gan_zhi = get_year_gan_zhi(date_test,observer_latitude,observer_longitude)
shi_gan_zhi = get_time_gan_zhi(date_test,observer_latitude,observer_longitude)
print(date_str + "中的年柱:"+year_gan_zhi)
print(date_str + "中的月柱:"+moon_gan_zhi)
print(date_str + "中的日柱:"+day_gan_zhi)
print(date_str + "中的时柱:"+shi_gan_zhi)

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值