西暦に基づいて旧暦を計算する。

41256 ワード

#! /usr/bin/env python3
# -*- coding:utf-8 -*-

# Author   : mayi
# Blog     : http://www.cnblogs.com/mayi0312/
# Date     : 2019/1/14
# Name     : test01
# Software : PyCharm
# Note     :                
#     
                
   python      qun,688244617
           、         。
     python                  python,       。
import datetime

#   g_lunar_month_day    1901  2050          ,
#        29 30 ,   12( 13)       ,    1 30 ,   29 
g_lunar_month_day = [
    0x4ae0, 0xa570, 0x5268, 0xd260, 0xd950, 0x6aa8, 0x56a0, 0x9ad0, 0x4ae8, 0x4ae0,   # 1910
    0xa4d8, 0xa4d0, 0xd250, 0xd548, 0xb550, 0x56a0, 0x96d0, 0x95b0, 0x49b8, 0x49b0,   # 1920
    0xa4b0, 0xb258, 0x6a50, 0x6d40, 0xada8, 0x2b60, 0x9570, 0x4978, 0x4970, 0x64b0,   # 1930
    0xd4a0, 0xea50, 0x6d48, 0x5ad0, 0x2b60, 0x9370, 0x92e0, 0xc968, 0xc950, 0xd4a0,   # 1940
    0xda50, 0xb550, 0x56a0, 0xaad8, 0x25d0, 0x92d0, 0xc958, 0xa950, 0xb4a8, 0x6ca0,   # 1950
    0xb550, 0x55a8, 0x4da0, 0xa5b0, 0x52b8, 0x52b0, 0xa950, 0xe950, 0x6aa0, 0xad50,   # 1960
    0xab50, 0x4b60, 0xa570, 0xa570, 0x5260, 0xe930, 0xd950, 0x5aa8, 0x56a0, 0x96d0,   # 1970
    0x4ae8, 0x4ad0, 0xa4d0, 0xd268, 0xd250, 0xd528, 0xb540, 0xb6a0, 0x96d0, 0x95b0,   # 1980
    0x49b0, 0xa4b8, 0xa4b0, 0xb258, 0x6a50, 0x6d40, 0xada0, 0xab60, 0x9370, 0x4978,   # 1990
    0x4970, 0x64b0, 0x6a50, 0xea50, 0x6b28, 0x5ac0, 0xab60, 0x9368, 0x92e0, 0xc960,   # 2000
    0xd4a8, 0xd4a0, 0xda50, 0x5aa8, 0x56a0, 0xaad8, 0x25d0, 0x92d0, 0xc958, 0xa950,   # 2010
    0xb4a0, 0xb550, 0xb550, 0x55a8, 0x4ba0, 0xa5b0, 0x52b8, 0x52b0, 0xa930, 0x74a8,   # 2020
    0x6aa0, 0xad50, 0x4da8, 0x4b60, 0x9570, 0xa4e0, 0xd260, 0xe930, 0xd530, 0x5aa0,   # 2030
    0x6b50, 0x96d0, 0x4ae8, 0x4ad0, 0xa4d0, 0xd258, 0xd250, 0xd520, 0xdaa0, 0xb5a0,   # 2040
    0x56d0, 0x4ad8, 0x49b0, 0xa4b8, 0xa4b0, 0xaa50, 0xb528, 0x6d20, 0xada0, 0x55b0,   # 2050
]

#   gLanarMonth    1901  2050      ,     0,      
g_lunar_month = [
    0x00, 0x50, 0x04, 0x00, 0x20,   # 1910
    0x60, 0x05, 0x00, 0x20, 0x70,   # 1920
    0x05, 0x00, 0x40, 0x02, 0x06,   # 1930
    0x00, 0x50, 0x03, 0x07, 0x00,   # 1940
    0x60, 0x04, 0x00, 0x20, 0x70,   # 1950
    0x05, 0x00, 0x30, 0x80, 0x06,   # 1960
    0x00, 0x40, 0x03, 0x07, 0x00,   # 1970
    0x50, 0x04, 0x08, 0x00, 0x60,   # 1980
    0x04, 0x0a, 0x00, 0x60, 0x05,   # 1990
    0x00, 0x30, 0x80, 0x05, 0x00,   # 2000
    0x40, 0x02, 0x07, 0x00, 0x50,   # 2010
    0x04, 0x09, 0x00, 0x60, 0x04,   # 2020
    0x00, 0x20, 0x60, 0x05, 0x00,   # 2030
    0x30, 0xb0, 0x06, 0x00, 0x50,   # 2040
    0x02, 0x07, 0x00, 0x50, 0x03    # 2050
]

#   
ly = '          '
#   
lm = '            '
#   
ld = '                                                            '

def strToDate(c_date):
    """
     8             
    :param c_date: 8      
    :return:        :   -1         ,   -2      ,       
    """
    if len(c_date) != 8:
        #         
        return -1
    #  
    year = int(c_date[:4])
    #  
    month = int(c_date[4:6])
    #  
    day = int(c_date[6:])
    try:
        d_date = datetime.date(int(year), int(month), int(day))
        return d_date
    except:
        #     ,    
        return -2

def lunarYearDays(year):
    """
              
    :param year:   (  )
    :return:     
    """
    days = 0
    for i in range(1, 13):
        (high, low) = lunarMonthDays(year, i)
        days += high
        days += low

    return days

def lunarMonthDays(year, month):
    """
                
    :param year:   (  )
    :param month:   (  )
    :return:   
    """
    if (year < 1901):
        return 30

    high, low = 0, 29
    iBit = 16 - month
    if (month > getLeapMonth(year)) and getLeapMonth(year):
        iBit -= 1
    if (g_lunar_month_day[year - 1901] & (1 << iBit)):
        low += 1
    if (month == getLeapMonth(year)):
        if (g_lunar_month_day[year - 1901] & (1 << (iBit - 1))):
            high = 30
        else:
            high = 29

    return (high, low)

def getLeapMonth(year):
    """
           ,   0,        
    :param year:   (  )
    :return:      ,       ,   0
    """
    flag = g_lunar_month[(year - 1901) // 2]
    if (year - 1901) % 2:
        return flag & 0x0f
    else:
        return flag >> 4

def lunarDate(d_date):
    """
                (   )
    :param d_date:     
    :return:     
    """
    #  1901.1.1  ,       
    delta_days = (d_date - datetime.date(1901, 1, 1)).days
    #   1901 02 19    1901     
    #   1901 01 01  1901 02 19   49 
    if delta_days < 49:
        year = 1901 - 1
        if delta_days < 19:
            month = 11
            day = delta_days + 11
        else:
            month = 12
            day = delta_days - 18
    else:
        #      1901       
        delta_days -= 49
        year, month, day = 1901, 1, 1
        #    
        temp = lunarYearDays(year)
        while delta_days >= temp:
            delta_days -= temp
            year += 1
            temp = lunarYearDays(year)
        #    
        (foo, temp) = lunarMonthDays(year, month)
        while delta_days >= temp:
            delta_days -= temp
            if (month == getLeapMonth(year)):
                (temp, foo) = lunarMonthDays(year, month)
                if (delta_days < temp):
                    year, month, day = 0, 0, 0
                delta_days -= temp
            month += 1
            (foo, temp) = lunarMonthDays(year, month)
        #    
        day += delta_days
    #                
    temp_year = str(year)
    year = ""
    for i in temp_year:
        year += ly[int(i)]

    return "  :%s %s %s" % (year, lm[month - 1], ld[(day - 1) * 2:day * 2])

#    
def main():
    #   8     (   )
    c_date = input("   8      ( :20180101):")
    #  8          
    d_date = strToDate(c_date)
    if d_date == -1:
        print("            !")
        return -1
    elif d_date == -2:
        print("            !")
        return -1
    #             
    l_date = lunarDate(d_date)
    #       、  
    print("  :%s" % (d_date))
    print(l_date)

#     
if __name__ == '__main__':
    main()
実験結果は以下の通りです。
   8      ( :20180101):201901142019-01-14