编程示例:公农历转换的算法

我国农历的编制与表示,在2017年,由中国科学院的南京的紫金山国家天文台发布了国家标准。
其中提到了编制规则。
第一以东八区的北京时间为准。
第二 朔日为农历月的第一个农历日
第三包含节气冬至在内的农历月为农历十一月。
第四若人某个农历十一月开始到下一个农历十一月(不含)之间有13个农历月,
则需要置闰月。置闰规则为取其中最先出现的一个不包含中气的农历月为农历闰月。
第五农历十一月之后第2个(不计闰月)农历月为农历年的起始月。

规则是既简明又准确的,就是不太好懂,我先解释一下,第一条定义了时间标准。
第二条定义了每个月的初一。第三条,俗称冬至规则,就是说,冬至那一天必须是在冬月,即农历十一月。
这一条至关重要,它是用公式推导其它农历月的基础。第四条包括了两个规则,(1)是是否置闰月的规则。
(2)是如何置闰月,这被叫做中气规则。这也是极为重要的一条规则。
第五条是定义了正月。

难点有两个,一是是否置闰月,它规定的年度期间为前一年的冬至到本年的冬至。然后看这个期间有多少个
朔日,也就是初一的数量,如果有十一个,没有闰月,如果是十二个,就是要闰月了。最佳的例子是2033年,
在公历的期间内也就是元旦到12月31日,它是有闰月的,闰11月。如果按照前一年的冬至到这一年的冬至期间
来看,它是没有闰月的。
二是置闰月的中气规则。还是举一个例子。以1987年为例,1987年8月24日为处暑,是农历七月初一,闰六月
如果是8月23日为处暑,则8月23日为农历七月的最后一天,8月24日是农历闰七月初一。
因为23日为处暑,它后面一个月之内缺中气秋分,所以闰七月。
因为24日为处暑,它前面一个月之内缺中气处暑,所以闰六月。

解释一下,什么是中气,24个节气中,出现在一个月的下旬的节气,称为中气,出现在一个月的上旬的节气,
称为节令。所以有12个节令,12个中气,节令和中气交替出现。它们合称24个节气。

下面要实现的功能是给出一个公历的年月日,返回一个农历的月和日。
javascript版本的api函数如下的调用方式
//输入阳历 2020 11 28 输出阴历 10月14日
 sun_to_moon(yyyy,mm,dd)

程序实现的源代码如下
//以1900年0月31日为起点,计算节气的积日
function accumute_day_for_year_term(year,xterm)
{
    var y=year-1900;
   return Math.floor(365.242*y+6.2+15.22*xterm-1.9*Math.sin(0.262*xterm));
}

以1900年0月31日为起点,计算某年元旦时的积日
function accumute_day_for_year_begin_date(year)
{ var d1=0;
    var y=year-1900;
    var ym4=y%4;
    var yd4=(y-ym4)/4;
    if(ym4==0)
    {d1=1461*yd4-1;}
    else
    {d1=1461*yd4+365*ym4;}
    return d1;
}

//求该积日的之前的最近的朔日的积日
function all_dark_day_for_coldest(d)
{
    var m=Math.floor(d/29.5306);
    var M_day=Math.floor(1.6+29.5306*m+0.4*Math.sin(1-0.45058*m));
    return M_day;
}

//判断是否是公历闰年,闰年为1,平年为0
function is_leap_year(years)
{
     if((years&3)!=0)
        {return 0;}
     else
         {if (years%100!=0)
            {return 1;}
           else
            {
                  if (year%400!=0)
                         {return 0;}
                  else
                        {return 1;}
            }              
        }
}

//判断是否是农历的有闰月年 ,有闰月为1,否则为0
function is_have_leap_month_of_year(year)
{
    var d0=accumute_day_for_year_term(year-1,23);
    var m0=Math.floor(d0/29.5306);
    var d=accumute_day_for_year_term(year,12*2-1);
    var m=m0+12+1;
   var str=all_dark_day_for_coldest(d);
   var   M_day=Math.floor(1.6+29.5306*m+0.4*Math.sin(1-0.45058*m));
   if(M_day>d)
   {
        var d1=accumute_day_for_year_term(year,1*2-1);
        var str1=all_dark_day_for_coldest(d1);
        if(str1>d1)
          {return 1;}
        else
          {return 0;}
   }
   else {return 1;}
}

//判断一个阴历月份范围内有没有中气,中气是冬至,大寒等位于下半月的节气。
// 结果为没有0,有中气返回1,中气在朔日结果是2。闰月之后的情况为3
function is_have_xterm_of_month(year,i)
{
   var d0=accumute_day_for_year_term(year-1,23);
   var m0=Math.floor(d0/29.5306);
   var d=accumute_day_for_year_term(year,i*2-1);
   var  m=m0+i+1;
   var  str=all_dark_day_for_coldest(d);
   var  M_day=Math.floor(1.6+29.5306*m+0.4*Math.sin(1-0.45058*m));
    if(str<d&&d<M_day) {return 1;}
    else if(str==d&&d<=M_day){return 2;}
    else if(str>d&&M_day>d){return 0;}
    else if(str<d&&str==M_day) {return 3;}
}

//在元旦作为起点 日期在年度中的天数  month 范围是1~12  日子范围是1——31。
function days_of_year_for_january(year,month,day)
{   var result=0;
    var monthadd=[0,31,59,90,120,151,181,212,243,273,304,334];
    var temp=is_leap_year(year);
    if(month==4||month==6||month==9||month==11)
    {if(day>30||day<1)
        {result="错误:日期超过范围";}
    }
    else if(month==2)
    {if(day>(28+temp)||day<1)
        {result="错误:日期超过范围";}
    }
    else
    {
        if(day>31||day<1)
        {result="错误:日期超过范围";}
    }

if((month==1||month==2)&&result==0)
        {
            result=monthadd[month-1]+day;
        }
    else if((month>2&&month<13)&&result==0)
        {
            result=monthadd[month-1]+day+temp;
        }
    else
    {
        if(month<1||month>12)
        {result+="错误:月份超过范围";}
    }    
    return  result;
}
//以3月1日作为起点 日期在年度中的天数
function days_of_year_for_march(month,day)
{
 var result=0;
    var monthadd=[306,337,0,31,61,92,122,153,184,214,245,275];
    
    if(month==4||month==6||month==9||month==11)
    {if(day>30||day<1)
        {result="错误:日期超过范围";}
    }
    else if(month==2)
    {if(day>29||day<1)
        {result="错误:日期超过范围";}
    }
    else
    {
        if(day>31||day<1)
        {result="错误:日期超过范围";}
    }

if((month>0&&month<13)&&result==0)
        {
            result=monthadd[month-1]+day;
        }
    else
    {
        if(month<1||month>12)
        {result+="错误:月份超过范围";}
    }    
    return  result;     
}

以1700年2月28日为起点,计算某年3月1日时的积日
function accumute_day_for_march(year)
{ var d1=0;
    var y=year-1700;
    var ym4=y%4;
    var yd4=(y-ym4)/4;
    if(ym4==0)
    {d1=1461*yd4;}
    else
    {d1=1461*yd4+365*ym4;}
    return d1;
}

//0为星期天,1-6为星期一到星期六
function day_of_week(y,m,d)
{
    var yy=y;
    if(m==1||m==2)
    {yy=y-1;}
  var acc= accumute_day_for_march(yy)+days_of_year_for_march(m,d);
  return (acc+5)%7;
}

//输入阳历 2020 11 28 输出阴历 10月14日
function sun_to_moon(yyyy,mm,dd)
{
var year=yyyy;
var month=mm;
var day=dd;

var d0=accumute_day_for_year_term(year-1,23);
 var m0=Math.floor(d0/29.5306);
 var result=[];
 var result_xterm=[];
 var result_month=0;
 var result_day=0;
 
 var d=accumute_day_for_year_term(year,1*2-1);
 var m=m0+1+1;
  var str=all_dark_day_for_coldest(d);
 var   M_day=Math.floor(1.6+29.5306*m+0.4*Math.sin(1-0.45058*m));
 var xterm=is_have_xterm_of_month(year,1);
 result_xterm.push(xterm);
 //result.push(str+" "+d+" "+M_day+" 腊月 "+xterm+String.fromCharCode(13)+String.fromCharCode(10));
  var current=accumute_day_for_year_begin_date(year)+days_of_year_for_january(year,month,day);
 if(str<=current&&current<=M_day)
  {result_month=12;
    result_day=current-str+1;
  }
 
 for(var i=2;i<13;i++)
 {var message='';
  var y_month=i-2;
  d=accumute_day_for_year_term(year,i*2-1);
  m=m0+i+1;
   str=all_dark_day_for_coldest(d);
    M_day=Math.floor(1.6+29.5306*m+0.4*Math.sin(1-0.45058*m));
    var xterm=is_have_xterm_of_month(year,i);
    
    if(result_xterm[result_xterm.length-1]==1&&xterm==2)
    {message="闰"+y_month+"月来了"
      m=m0+i;
      M_day=Math.floor(1.6+29.5306*m+0.4*Math.sin(1-0.45058*m));
      if(M_day<=current&&current<str)
      {result_month="闰"+y_month;
       result_day=current-M_day+1;
      }
      
       var ii=i-1;
        m=m0+i+2;
        M_day=Math.floor(1.6+29.5306*m+0.4*Math.sin(1-0.45058*m));
      if(str<=current&&current<M_day)
      {result_month=ii;
       result_day=current-str+1;
      }
    }
    else if(xterm==3)
    {  var ii=i-1;
        m=m0+i+2;
        M_day=Math.floor(1.6+29.5306*m+0.4*Math.sin(1-0.45058*m));
      if(str<=current&&current<=M_day)
      {result_month=ii;
       result_day=current-str+1;
      }
    }
    else if(xterm==1)
    {var ii=i-1;
      if(str<=current&&current<=M_day)
      {result_month=ii;
       result_day=current-str+1;
      }
    }
    
 //result.push(str+" "+d+" "+M_day+" "+ii+"月 "+xterm+" "+message+String.fromCharCode(13)+String.fromCharCode(10));    
 }
 
  //document.getElementById("txt2").innerText=
  return result_month+"月"+result_day+"日";
}

编程示例:公农历转换的算法相关推荐

  1. 公农历转换和获取二十四节气算法

    用C51单片机做一个万年历的显示:涉及到公农历的转换以及获取对应二十四节气的方法的问题. 二十四节气的存储方法和数据是本人一个个算的哦,如果对大家有帮助的话,求赞+关注! 年份信息和二十四节气信息存储 ...

  2. 微信小程序 - 公农历通用时间选择器组件

    GitHub Demo 地址: jh-weapp-demo 实现一些常用效果.封装通用组件和工具类 小程序码 序 最近做了个小程序,需要用到支持公农历的通用时间选择器,找了一圈没有现成的,只能自己撸一 ...

  3. EOS智能合约开发(四)EOS智能合约部署及调试(附编程示例)

    EOS的智能合约里面有一个action(动作)和transaction(交易)的概念. 对于我们开发以太坊开发者来说,基本上只有transaction的概念.如果我只要执行一种操作,而且是只读操作,就 ...

  4. php转字,PHP汉字拼音转换和公历农历转换

    1.PHP汉字转拼音 Pinyin.class.php类文件可以将大多数汉字转换成汉语拼音,当然也有个别生僻字不能转换,如果你想转换所有的汉字拼音的话,可能需要再配合一个汉字字库来实现,使用该类文件就 ...

  5. python年份天干地支代码_农历天干地支算法源代码大全(javascript、vbscript、C#、flash、C++、C等等【转】...

    文章提供计算农历天干地支及当年属相的算法源程序,使用的语言为Javascript.VBScript.C#等. 一.C# 代码(1): 原来还准备自己写算法,并研究农历规则.发现那太难和麻烦了,光是农历 ...

  6. PHP汉字拼音转换和公历农历转换

    本文整理了PHP汉字拼音转换和公历农历转换两个功能类文件,非常实用.比如我们查找通讯录可以通过联系人姓名的拼音首字母来查询,可以通过首字母来导航大数据量,可以通过转换拼音来做网站优化等.公农历转化一般 ...

  7. PHP汉字拼音转换和公历农历转换(代码家园)

    本文整理了PHP汉字拼音转换和公历农历转换两个功能类文件,非常实用.比如我们查找通讯录可以通过联系人姓名的拼音首字母来查询,可以通过首字母来导航大数据量,可以通过转换拼音来做网站优化等.公农历转化一般 ...

  8. C语言与OpenCL的编程示例比较

    C语言与OpenCL的编程示例比较 OpenCL支持数据并行,任务并行编程,同时支持两种模式的混合.对于同步 OpenCL支持同一工作组内工作项的同步和命令队列中处于同一个上下文中的 命令的同步. 在 ...

  9. Muduo 网络编程示例之五: 测量两台机器的网络延迟

    Muduo 网络编程示例之五: 测量两台机器的网络延迟 陈硕 (giantchen_AT_gmail) Blog.csdn.net/Solstice  t.sina.com.cn/giantchen ...

  10. 转:Kafka事务使用和编程示例/实例

    Kafka事务使用和编程示例/实例_JobShow裁员加班实况-微信小程序-CSDN博客一.概述​ Kafka事务特性是指一系列的生产者生产消息和消费者提交偏移量的操作在一个事务中,或者说是一个原子操 ...

最新文章

  1. 模糊神经网络工具箱函数使用
  2. Go连接MySql数据库too many connections
  3. mysql 内存溢出_mysql - MySQL在非常大的表上计算性能 - 堆栈内存溢出
  4. 使用jquery时一些小技巧的总结
  5. confluence添加用户_玩转Confluence插件开发插件模块配置文件介绍(04)
  6. 数字电路设计200例_惊险!200米高空,quot;蜘蛛侠quot;救quot;蜘蛛人quot;!
  7. Nginx学习总结(14)——Nginx配置参数详细说明与整理
  8. 寻找数组中 的最大值最小值
  9. leetcode 动态规划 —— 53(最大子序列的和)
  10. 【Java程序设计】异常处理
  11. 敏捷开发中XP与SCRUM的区别
  12. 计算机派位志愿填报技巧,小升初电脑派位 填报也有技巧
  13. (附源码)spring boot小说网站系统 毕业设计 041446
  14. 页面置换算法java_页面置换算法之Clock算法
  15. JavaScript 打开新页面
  16. php ctype xdigit,php ctype_digit() 函数介绍
  17. 【ps功能精通】6.钢笔工具
  18. 计算机毕业设计Java新疆旅游专列订票系统(源码+系统+mysql数据库+Lw文档)
  19. STM32配置组合设备(HID+CDC)
  20. Hello New World 写在 Conflux 网络 Tethys 上线之际

热门文章

  1. php aria2离线下载器,下载神器——Aria2,打造你自己的离线下载服务器
  2. 测量电流传感器的放大倍数
  3. Alpha 完结撒花 —— 事后诸葛亮
  4. Linux 流量监控
  5. 北航超算运行matlab,北航荣获世界大学生超算总决赛一等奖!超50万亿次,又破世界纪录...
  6. 我的世界高分辨率/512x/1024x/2048x材质包制作教程:Substance 3D Designer
  7. excel单元格斜线_Excel 表格中斜线怎么制作?
  8. Cypress初探(一)
  9. 从qire123上抓取bdhd下载地址的firefox extension
  10. 滴滴宋世君:数据分析师究竟是做什么的?