农历日期与阳历日期互转

阳历日期与农历日期互转

背景

SAP HCM需要一个根据农历春节所在的阳历日期的月份来决定是否计算13薪。
搜索之后发现农历日期没有固定的数学计算规则,是根据地球公转来的。具体过程比较复杂。现在大部分的万年历其实都只能查到农历1900-2100年,这些数据可以从香港天文台公曆與農曆日期對照表下载。
经过搜索发现其他编程语言实现的万年历或者公历日期转农历日期的项目比较多而且很成熟,有些还包含24节气信息。而ABAP语言的只搜到两个,一个是report程序,没有注释文档懒得看代码。另一个是一个Function,但是不能直接拿来使用,作者没有提供Function所使用的农历年日期数据。鉴于此,只好自己实现一个。

项目简介

使用如下的内表存农历年数据,字段spring_solar_date存农历春节对应的公历日期,字段lunar存农历的二进制信息。

  BEGIN OF ys_lunar_year,
    spring_solar_date TYPE d,
    lunar             TYPE x LENGTH 3,
  END OF ys_lunar_year .
 TYPES:
   yt_lunar_year TYPE TABLE OF ys_lunar_year .

 CLASS-DATA lunar_year TYPE yt_lunar_year .

例如:1900年二进制信息:
二进制位编号:1--------------------------------------------24
农历年二进制:0000-0100–1011- 1101–0000-1000

1-4bit位没有使用;
5-16bit位表示农历年的1-12月每个月的天数,值为0表示29天,值为1表示30天;
17-19bit位没有使用;
20bit位表示闰月的天数,值为0表示29天,值为1表示30天;
21-24位的值表示闰月的月份数值,值为0表示当年没有闰月;

项目含有农历年1900-2100总共201个农历年的信息。数据在类构造器中进行初始化。

类工具方法简介

农历日期转公历日期

方法:GET_LUNAR根据输入的公历日期推算得出对应的农历日期,如果是闰月设置参数IS_LEAP_MONTH的值为X,否者为空。
农历日期与阳历日期互转

公历日期转农历日期

方法:GET_SOLAR根据输入的农历日期推算得出对应的公历日期,如果指定的是闰月需要设置输入参数IS_LEAP_MONTH的值为X,否者为空。
农历日期与阳历日期互转

项目Github地址

阳历与农历日期互转github地址https://github.com/Define2017/SolarDate_convert_LunarDate

代码

class ZCL_DATE_TOOL0 definition
  public
  final
  create public .

public section.
  class-methods CLASS_CONSTRUCTOR .
  class-methods GET_LUNAR
    importing
      !SOLAR_DATE type D default SY-DATUM
    exporting
      !ISLEAP_MONTH type CHAR1
    returning
      value(LUNAR_DATE) type NUM08 .
  class-methods GET_SOLAR
    importing
      !LUNAR_DATE type NUM08
      !ISLEAP_MONTH type CHAR1 default ''
    returning
      value(SOLAR_DATE) type D .
protected section.
PRIVATE SECTION.
  TYPES:
    BEGIN OF ys_lunar_year,
      spring_solar_date TYPE d,
      lunar             TYPE x LENGTH 3,
    END OF ys_lunar_year .
  TYPES:
    yt_lunar_year TYPE TABLE OF ys_lunar_year .

  CLASS-DATA lunar_year TYPE yt_lunar_year .
ENDCLASS.

CLASS ZCL_DATE_TOOL0 IMPLEMENTATION.

  METHOD CLASS_CONSTRUCTOR.
    IF lunar_year IS INITIAL.
      "field SPRING_SOLAR_DATE storage Solar date of Spring Festival
      "field LUNAR storage Lunar Year binary code,the length is 3 Byte
      "eg.
      "1900 year info
      "  Bit-Num 1234 5678  9ABC DEFG  HIJK LMNO
      " Byte-Seq 0000-0100--1011-1101--0000-1000
      "the 1-4 bit place is not use
      "the 5-16 bit place is days number of 1-12 month per month of
      "Lunar Year, and bit place value is 0 symbol 29 days,
      "value is 1 symbol 30.
      "the 17-19 bit place is not use
      "the 20 bit place is symbol days number of leap month, and
      " bit place value is 0 symbol 29 days, value is 1 symbol 30.
      "the 21-24 bit place is symbol month number of leap month
      lunar_year = VALUE #(
        ( spring_solar_date = '19000131' lunar = '04BD08' )
        ( spring_solar_date = '19010219' lunar = '04AE00' )
        ( spring_solar_date = '19020208' lunar = '0A5700' )
        ( spring_solar_date = '19030129' lunar = '054D05' )
        ( spring_solar_date = '19040216' lunar = '0D2600' )
        ( spring_solar_date = '19050204' lunar = '0D9500' )
        ( spring_solar_date = '19060125' lunar = '065514' )
        ( spring_solar_date = '19070213' lunar = '056A00' )
        ( spring_solar_date = '19080202' lunar = '09AD00' )
        ( spring_solar_date = '19090122' lunar = '055D02' )
        ( spring_solar_date = '19100210' lunar = '04AE00' )
        ( spring_solar_date = '19110130' lunar = '0A5B06' )
        ( spring_solar_date = '19120218' lunar = '0A4D00' )
        ( spring_solar_date = '19130206' lunar = '0D2500' )
        ( spring_solar_date = '19140126' lunar = '0D2515' )
        ( spring_solar_date = '19150214' lunar = '0B5400' )
        ( spring_solar_date = '19160203' lunar = '0D6A00' )
        ( spring_solar_date = '19170123' lunar = '0ADA02' )
        ( spring_solar_date = '19180211' lunar = '095B00' )
        ( spring_solar_date = '19190201' lunar = '049717' )
        ( spring_solar_date = '19200220' lunar = '049700' )
        ( spring_solar_date = '19210208' lunar = '0A4B00' )
        ( spring_solar_date = '19220128' lunar = '0B4B05' )
        ( spring_solar_date = '19230216' lunar = '06A500' )
        ( spring_solar_date = '19240205' lunar = '06D400' )
        ( spring_solar_date = '19250124' lunar = '0AB514' )
        ( spring_solar_date = '19260213' lunar = '02B600' )
        ( spring_solar_date = '19270202' lunar = '095700' )
        ( spring_solar_date = '19280123' lunar = '052F02' )
        ( spring_solar_date = '19290210' lunar = '049700' )
        ( spring_solar_date = '19300130' lunar = '065606' )
        ( spring_solar_date = '19310217' lunar = '0D4A00' )
        ( spring_solar_date = '19320206' lunar = '0EA500' )
        ( spring_solar_date = '19330126' lunar = '06A915' )
        ( spring_solar_date = '19340214' lunar = '05AD00' )
        ( spring_solar_date = '19350204' lunar = '02B600' )
        ( spring_solar_date = '19360124' lunar = '086E13' )
        ( spring_solar_date = '19370211' lunar = '092E00' )
        ( spring_solar_date = '19380131' lunar = '0C8D17' )
        ( spring_solar_date = '19390219' lunar = '0C9500' )
        ( spring_solar_date = '19400208' lunar = '0D4A00' )
        ( spring_solar_date = '19410127' lunar = '0D8A16' )
        ( spring_solar_date = '19420215' lunar = '0B5500' )
        ( spring_solar_date = '19430205' lunar = '056A00' )
        ( spring_solar_date = '19440125' lunar = '0A5B14' )
        ( spring_solar_date = '19450213' lunar = '025D00' )
        ( spring_solar_date = '19460202' lunar = '092D00' )
        ( spring_solar_date = '19470122' lunar = '0D2B02' )
        ( spring_solar_date = '19480210' lunar = '0A9500' )
        ( spring_solar_date = '19490129' lunar = '0B5507' )
        ( spring_solar_date = '19500217' lunar = '06CA00' )
        ( spring_solar_date = '19510206' lunar = '0B5500' )
        ( spring_solar_date = '19520127' lunar = '053515' )
        ( spring_solar_date = '19530214' lunar = '04DA00' )
        ( spring_solar_date = '19540203' lunar = '0A5B00' )
        ( spring_solar_date = '19550124' lunar = '045713' )
        ( spring_solar_date = '19560212' lunar = '052B00' )
        ( spring_solar_date = '19570131' lunar = '0A9A08' )
        ( spring_solar_date = '19580218' lunar = '0E9500' )
        ( spring_solar_date = '19590208' lunar = '06AA00' )
        ( spring_solar_date = '19600128' lunar = '0AEA06' )
        ( spring_solar_date = '19610215' lunar = '0AB500' )
        ( spring_solar_date = '19620205' lunar = '04B600' )
        ( spring_solar_date = '19630125' lunar = '0AAE04' )
        ( spring_solar_date = '19640213' lunar = '0A5700' )
        ( spring_solar_date = '19650202' lunar = '052600' )
        ( spring_solar_date = '19660121' lunar = '0F2603' )
        ( spring_solar_date = '19670209' lunar = '0D9500' )
        ( spring_solar_date = '19680130' lunar = '05B507' )
        ( spring_solar_date = '19690217' lunar = '056A00' )
        ( spring_solar_date = '19700206' lunar = '096D00' )
        ( spring_solar_date = '19710127' lunar = '04DD05' )
        ( spring_solar_date = '19720215' lunar = '04AD00' )
        ( spring_solar_date = '19730203' lunar = '0A4D00' )
        ( spring_solar_date = '19740123' lunar = '0D4D04' )
        ( spring_solar_date = '19750211' lunar = '0D2500' )
        ( spring_solar_date = '19760131' lunar = '0D5508' )
        ( spring_solar_date = '19770218' lunar = '0B5400' )
        ( spring_solar_date = '19780207' lunar = '0B6A00' )
        ( spring_solar_date = '19790128' lunar = '095A16' )
        ( spring_solar_date = '19800216' lunar = '095B00' )
        ( spring_solar_date = '19810205' lunar = '049B00' )
        ( spring_solar_date = '19820125' lunar = '0A9704' )
        ( spring_solar_date = '19830213' lunar = '0A4B00' )
        ( spring_solar_date = '19840202' lunar = '0B270A' )
        ( spring_solar_date = '19850220' lunar = '06A500' )
        ( spring_solar_date = '19860209' lunar = '06D400' )
        ( spring_solar_date = '19870129' lunar = '0AF406' )
        ( spring_solar_date = '19880217' lunar = '0AB600' )
        ( spring_solar_date = '19890206' lunar = '095700' )
        ( spring_solar_date = '19900127' lunar = '04AF05' )
        ( spring_solar_date = '19910215' lunar = '049700' )
        ( spring_solar_date = '19920204' lunar = '064B00' )
        ( spring_solar_date = '19930123' lunar = '074A03' )
        ( spring_solar_date = '19940210' lunar = '0EA500' )
        ( spring_solar_date = '19950131' lunar = '06B508' )
        ( spring_solar_date = '19960219' lunar = '05AC00' )
        ( spring_solar_date = '19970207' lunar = '0AB600' )
        ( spring_solar_date = '19980128' lunar = '096D05' )
        ( spring_solar_date = '19990216' lunar = '092E00' )
        ( spring_solar_date = '20000205' lunar = '0C9600' )
        ( spring_solar_date = '20010124' lunar = '0D9504' )
        ( spring_solar_date = '20020212' lunar = '0D4A00' )
        ( spring_solar_date = '20030201' lunar = '0DA500' )
        ( spring_solar_date = '20040122' lunar = '075502' )
        ( spring_solar_date = '20050209' lunar = '056A00' )
        ( spring_solar_date = '20060129' lunar = '0ABB07' )
        ( spring_solar_date = '20070218' lunar = '025D00' )
        ( spring_solar_date = '20080207' lunar = '092D00' )
        ( spring_solar_date = '20090126' lunar = '0CAB05' )
        ( spring_solar_date = '20100214' lunar = '0A9500' )
        ( spring_solar_date = '20110203' lunar = '0B4A00' )
        ( spring_solar_date = '20120123' lunar = '0BAA04' )
        ( spring_solar_date = '20130210' lunar = '0AD500' )
        ( spring_solar_date = '20140131' lunar = '055D09' )
        ( spring_solar_date = '20150219' lunar = '04BA00' )
        ( spring_solar_date = '20160208' lunar = '0A5B00' )
        ( spring_solar_date = '20170128' lunar = '051716' )
        ( spring_solar_date = '20180216' lunar = '052B00' )
        ( spring_solar_date = '20190205' lunar = '0A9300' )
        ( spring_solar_date = '20200125' lunar = '079504' )
        ( spring_solar_date = '20210212' lunar = '06AA00' )
        ( spring_solar_date = '20220201' lunar = '0AD500' )
        ( spring_solar_date = '20230122' lunar = '05B502' )
        ( spring_solar_date = '20240210' lunar = '04B600' )
        ( spring_solar_date = '20250129' lunar = '0A6E06' )
        ( spring_solar_date = '20260217' lunar = '0A4E00' )
        ( spring_solar_date = '20270206' lunar = '0D2600' )
        ( spring_solar_date = '20280126' lunar = '0EA605' )
        ( spring_solar_date = '20290213' lunar = '0D5300' )
        ( spring_solar_date = '20300203' lunar = '05AA00' )
        ( spring_solar_date = '20310123' lunar = '076A03' )
        ( spring_solar_date = '20320211' lunar = '096D00' )
        ( spring_solar_date = '20330131' lunar = '04AF0B' )
        ( spring_solar_date = '20340219' lunar = '04AD00' )
        ( spring_solar_date = '20350208' lunar = '0A4D00' )
        ( spring_solar_date = '20360128' lunar = '0D0B16' )
        ( spring_solar_date = '20370215' lunar = '0D2500' )
        ( spring_solar_date = '20380204' lunar = '0D5200' )
        ( spring_solar_date = '20390124' lunar = '0DD405' )
        ( spring_solar_date = '20400212' lunar = '0B5A00' )
        ( spring_solar_date = '20410201' lunar = '056D00' )
        ( spring_solar_date = '20420122' lunar = '055B02' )
        ( spring_solar_date = '20430210' lunar = '049B00' )
        ( spring_solar_date = '20440130' lunar = '0A5707' )
        ( spring_solar_date = '20450217' lunar = '0A4B00' )
        ( spring_solar_date = '20460206' lunar = '0AA500' )
        ( spring_solar_date = '20470126' lunar = '0B2515' )
        ( spring_solar_date = '20480214' lunar = '06D200' )
        ( spring_solar_date = '20490202' lunar = '0ADA00' )
        ( spring_solar_date = '20500123' lunar = '04B613' )
        ( spring_solar_date = '20510211' lunar = '093700' )
        ( spring_solar_date = '20520201' lunar = '049F08' )
        ( spring_solar_date = '20530219' lunar = '049700' )
        ( spring_solar_date = '20540208' lunar = '064B00' )
        ( spring_solar_date = '20550128' lunar = '068A16' )
        ( spring_solar_date = '20560215' lunar = '0EA500' )
        ( spring_solar_date = '20570204' lunar = '06AA00' )
        ( spring_solar_date = '20580124' lunar = '0A6C14' )
        ( spring_solar_date = '20590212' lunar = '0AAE00' )
        ( spring_solar_date = '20600202' lunar = '092E00' )
        ( spring_solar_date = '20610121' lunar = '0D2E03' )
        ( spring_solar_date = '20620209' lunar = '0C9600' )
        ( spring_solar_date = '20630129' lunar = '0D5507' )
        ( spring_solar_date = '20640217' lunar = '0D4A00' )
        ( spring_solar_date = '20650205' lunar = '0DA500' )
        ( spring_solar_date = '20660126' lunar = '05D505' )
        ( spring_solar_date = '20670214' lunar = '056A00' )
        ( spring_solar_date = '20680203' lunar = '0A6D00' )
        ( spring_solar_date = '20690123' lunar = '055D04' )
        ( spring_solar_date = '20700211' lunar = '052D00' )
        ( spring_solar_date = '20710131' lunar = '0A9B08' )
        ( spring_solar_date = '20720219' lunar = '0A9500' )
        ( spring_solar_date = '20730207' lunar = '0B4A00' )
        ( spring_solar_date = '20740127' lunar = '0B6A06' )
        ( spring_solar_date = '20750215' lunar = '0AD500' )
        ( spring_solar_date = '20760205' lunar = '055A00' )
        ( spring_solar_date = '20770124' lunar = '0ABA04' )
        ( spring_solar_date = '20780212' lunar = '0A5B00' )
        ( spring_solar_date = '20790202' lunar = '052B00' )
        ( spring_solar_date = '20800122' lunar = '0B2703' )
        ( spring_solar_date = '20810209' lunar = '069300' )
        ( spring_solar_date = '20820129' lunar = '073307' )
        ( spring_solar_date = '20830217' lunar = '06AA00' )
        ( spring_solar_date = '20840206' lunar = '0AD500' )
        ( spring_solar_date = '20850126' lunar = '04B515' )
        ( spring_solar_date = '20860214' lunar = '04B600' )
        ( spring_solar_date = '20870203' lunar = '0A5700' )
        ( spring_solar_date = '20880124' lunar = '054E04' )
        ( spring_solar_date = '20890210' lunar = '0D1600' )
        ( spring_solar_date = '20900130' lunar = '0E9608' )
        ( spring_solar_date = '20910218' lunar = '0D5200' )
        ( spring_solar_date = '20920207' lunar = '0DAA00' )
        ( spring_solar_date = '20930127' lunar = '06AA16' )
        ( spring_solar_date = '20940215' lunar = '056D00' )
        ( spring_solar_date = '20950205' lunar = '04AE00' )
        ( spring_solar_date = '20960125' lunar = '0A9D04' )
        ( spring_solar_date = '20970212' lunar = '0A2D00' )
        ( spring_solar_date = '20980201' lunar = '0D1500' )
        ( spring_solar_date = '20990121' lunar = '0F2502' )
        ( spring_solar_date = '21000209' lunar = '0D5200' )
        ).
    ENDIF.
  ENDMETHOD.

  METHOD GET_LUNAR.
    CHECK solar_date >= '19000131' AND solar_date <= '21010129'.

    " index of line symbol year number
    DATA(l_year_index) = ( CONV i( solar_date+0(4) ) - 1900 ) + 1.
    DATA(l_spring) = lunar_year[ l_year_index ]-spring_solar_date.
    IF l_spring > solar_date.
      l_year_index = l_year_index - 1.
      l_spring = lunar_year[ l_year_index ]-spring_solar_date.
    ENDIF.
    DATA(l_lunaryear_code) = lunar_year[ l_year_index ]-lunar.
    "solar date distance date of Spring Festival
    DATA(l_distance) = solar_date - l_spring + 1.
    "Get date is Spring Festival
    IF l_distance = 1.
      lunar_date = |{ l_spring+0(4) }0101|.
      RETURN.
    ENDIF.
    " Get days number of leap month, and month number of leap month
    GET BIT 20 OF l_lunaryear_code INTO DATA(l_bin).
    DATA(l_leap_month_days) = COND i( WHEN l_bin = 0 THEN 29 ELSE 30 ).
    DATA(l_leap_month) = l_lunaryear_code BIT-AND
      CONV xstring( '00000F' ).

    WHILE 0 = 0.
      DATA(l_index) = sy-index.

      GET BIT ( l_index + 4 ) OF l_lunaryear_code INTO l_bin.
      DATA(l_month_days) = COND i( WHEN l_bin = 0 THEN 29 ELSE 30 ).

      IF l_distance - l_month_days <= 0.

        lunar_date = |{ l_spring+0(4) }{ CONV num02( l_index )
          WIDTH = 2 }{ CONV num02( l_distance ) WIDTH = 2 }|.
        EXIT.
      ENDIF.
      l_distance = l_distance - l_month_days.

      CHECK CONV i( l_leap_month ) = l_index." When leap month
      IF l_distance - l_leap_month_days <= 0.

        lunar_date = |{ l_spring+0(4) }{ CONV num02( l_index )
          WIDTH = 2 }{ CONV num02( l_distance ) WIDTH = 2 }|.
        isleap_month = abap_true.
        EXIT.
      ENDIF.
      l_distance = l_distance - l_leap_month_days.
    ENDWHILE.
  ENDMETHOD.

  METHOD GET_SOLAR.
    CHECK lunar_date >= '19000101' AND lunar_date <= '21001229'.

    " sequence Lunar Date
    DATA(l_month) = CONV i( lunar_date+4(2) ).
    DATA(l_day) = CONV i( lunar_date+6(2) ).
    " index of line symbol year number
    DATA(l_year_index) = ( CONV i( lunar_date+0(4) ) - 1900 ) + 1.
    DATA(l_spring) = lunar_year[ l_year_index ]-spring_solar_date.
    DATA(l_lunaryear_code) = lunar_year[ l_year_index ]-lunar.
    "Get date is Spring Festival
    IF lunar_date+4(4) = '0101'.
      solar_date = l_spring.
      RETURN.
    ENDIF.
    " Get Get days number of leap month, and month number of leap month
    GET BIT 20 OF l_lunaryear_code INTO DATA(l_bin).
    DATA(l_leap_month_days) = COND i( WHEN l_bin = 0 THEN 29 ELSE 30 ).
    DATA(l_leap_month) = l_lunaryear_code BIT-AND
      CONV xstring( '00000F' ).
    " Check Luanar
    IF isleap_month = abap_true.
      CHECK l_month = CONV i( l_leap_month ) AND l_day <= l_leap_month_days.
    ELSE.
      GET BIT ( l_month + 4 ) OF l_lunaryear_code INTO l_bin.
      DATA(l_month_days) = COND i( WHEN l_bin = 0 THEN 29 ELSE 30 ).
      CHECK l_day <= l_month_days.
    ENDIF.
    "Lunar date distance date of Spring Festival
    DATA(l_distance) = 0.
    WHILE 0 = 0.
      DATA(l_index) = sy-index.

      GET BIT ( l_index + 4 ) OF l_lunaryear_code INTO l_bin.
      l_month_days = COND i( WHEN l_bin = 0 THEN 29 ELSE 30 ).
      IF l_month = sy-index AND isleap_month = abap_false.
        l_distance = l_distance + l_day.
        EXIT.
      ENDIF.
      l_distance = l_distance + l_month_days.

      CHECK CONV i( l_leap_month ) = l_index." When leap month
      IF l_month = sy-index AND isleap_month = abap_true.
        l_distance = l_distance + l_day.
        EXIT.
      ENDIF.
      l_distance = l_distance + l_leap_month_days.
    ENDWHILE.
    
    solar_date = l_spring + l_distance - 1.
  ENDMETHOD.
ENDCLASS.

上一篇:【Codeforces 1106E】Lunar New Year and Red Envelopes


下一篇:[SUCTF 2019]EasySQL