相关概念

1,阳历–以地球绕太阳一周为一年所定出的历法.

2,阴历–以太阴(月亮)绕地球为一个月,12个月为一年(闰年为13个月)所定出来的历法.(以闰月调节年之四时).

思路解析

(y % 12 +8) %12

(y % 12 -4) %12

(y -4) %12

怎样计算天干地支

(1900 -4) % 10 =6 ===>庚

(1900-4) % 12 =4 ===>子

(y-4) % 10 ==>天干对应的位置编号

(y-4) % 12 ==>地支对应的位置编号

具体实现

``````<?php
/**
*author:dequan
*date:2016-06-20
*原文地址:http://blog.csdn.net/hsd2012/article/details/51701640
*/
class Calendar{
private \$animals=array("鼠","牛","虎","兔","龙","蛇","马","羊","猴","鸡","狗","猪");
private \$curData=null;//当前阳历时间
private \$ylYeal=0;
private \$ylMonth=0;
private \$yldate=0;
private \$ylDays=0; //当前日期是农历年的第多少天
private \$leap=0;//代表润哪一个月
private \$leapDays=0;//代表闰月的天数
private \$difmonth=0;//当前时间距离参考时间相差多少月
private \$difDay=0;//当前时间距离参考时间相差多少天
private \$tianGan=array("甲","乙","丙","丁","戊","己","庚","辛","壬","癸");
private \$diZhi=array("子","丑","寅","卯","辰","巳","午","未","申","酉","戌","亥");
0x04970,0x0a4b0,0x0b4b5,0x06a50,0x06d40,0x1ab54,0x02b60,0x09570,0x052f2,0x04970,//1920-1929
0x0d4a0,0x1d8a6,0x0b550,0x056a0,0x1a5b4,0x025d0,0x092d0,0x0d2b2,0x0a950,0x0b557,//1940-1949
0x06ca0,0x0b550,0x15355,0x04da0,0x0a5b0,0x14573,0x052b0,0x0a9a8,0x0e950,0x06aa0,//1950-1959
0x0aea6,0x0ab50,0x04b60,0x0aae4,0x0a570,0x05260,0x0f263,0x0d950,0x05b57,0x056a0,//1960-1969
0x095b0,0x049b0,0x0a974,0x0a4b0,0x0b27a,0x06a50,0x06d40,0x0af46,0x0ab60,0x09570,//1980-1989
0x04af5,0x04970,0x064b0,0x074a3,0x0ea50,0x06b58,0x055c0,0x0ab60,0x096d5,0x092e0,//1990-1999
0x0c960,0x0d954,0x0d4a0,0x0da50,0x07552,0x056a0,0x0abb7,0x025d0,0x092d0,0x0cab5,//2000-2009
0x14b63,0x09370,0x049f8,0x04970,0x064b0,0x168a6,0x0ea50, 0x06b20,0x1a6c4,0x0aae0,//2050-2059
0x0a2e0,0x0d2e3,0x0c960,0x0d557,0x0d4a0,0x0da50,0x05d55,0x056a0,0x0a6d0,0x055d4,//2060-2069
0x0e968,0x0d520,0x0daa0,0x16aa6,0x056d0,0x04ae0,0x0a9d4,0x0a2d0,0x0d150,0x0f252,//2090-2099
0x0d520);
public function __construct(\$curData=null){
if(!empty(\$curData)){
\$this->curData=\$curData;
}else{
\$this->curData=date(‘Y-n-j‘);
}
\$this->init();
}

public function init(){
\$basedate=‘1900-1-31‘;//参照日期
\$timezone=‘PRC‘;
\$datetime= new DateTime(\$basedate, new DateTimeZone(\$timezone));
\$curTime=new DateTime(\$this->curData, new DateTimeZone(\$timezone));
\$offset   = (\$curTime->format(‘U‘) - \$datetime->format(‘U‘))/86400; //相差的天数
\$offset=ceil(\$offset);
\$this->difDay=\$offset;
\$offset+=1;//只能使用ceil，不能使用intval或者是floor,因为1900-1-31为正月初一，故需要加1
for(\$i=1900; \$i<2050 && \$offset>0; \$i++){
\$temp = \$this->getYearDays(\$i); //计算i年有多少天
\$offset -= \$temp ;
\$this->difmonth+=12;
//判断该年否存在闰月
if(\$this->leapMonth(\$i)>0){
\$this->difmonth+=1;
}
}

if(\$offset<0){
\$offset += \$temp;
\$i--;
\$this->difmonth-=12;
}
if(\$this->leapMonth(\$i)>0){
\$this->difmonth-=1;
}
\$this->ylDays=\$offset;
//此时\$offset代表是农历该年的第多少天
\$this->ylYeal=\$i;//农历哪一年
//计算月份，依次减去1~12月份的天数，直到offset小于下个月的天数
\$curMonthDays=\$this->monthDays(\$this->ylYeal,1);
//判断是否该年是否存在闰月以及闰月的天数
\$this->leap=\$this->leapMonth(\$this->ylYeal);
if(\$this->leap !=0){
\$this->leapDays=\$this->leapDays(\$this->ylYeal);
}

for(\$i=1;\$i<13 && \$curMonthDays<\$offset;\$curMonthDays=\$this->monthDays(\$this->ylYeal,++\$i)){
if(\$this->leap == \$i){ //闰月
if(\$offset>\$this->leapDays){
--\$i;
\$offset-=\$this->leapDays;
\$this->difmonth+=1;
}else{
break;
}
}else{
\$offset-=\$curMonthDays;
\$this->difmonth+=1;
}
}

\$this->ylMonth=\$i;
\$this->yldate=\$offset;
}
/**
*计算农历y年有多少天
**/
public function getYearDays(\$y){
\$sum = 348;//12*29=348,不考虑小月的情况下
for(\$i=0x8000; \$i>=0x10; \$i>>=1){
\$sum += (\$this->dataInfo[\$y-1900] & \$i)? 1: 0;
}
return(\$sum+\$this->leapDays(\$y));
}
/**
*获取某一年闰月的天数
**/
public function leapDays(\$y){
if(\$this->leapMonth(\$y)){
return((\$this->dataInfo[\$y-1900] & 0x10000)? 30: 29);

} else {
return(0);
}
}
/**
*计算哪一月为闰月
*/
public  function leapMonth(\$y){
return (\$this->dataInfo[\$y-1900] & 0xf);
}
/**
*计算农历y年m月有多少天
*/
public function monthDays(\$y,\$m){
return ((\$this->dataInfo[\$y-1900] & (0x10000>>\$m))? 30: 29 );
}

public function getLyTime(){
\$tmp=array(‘初‘,‘一‘,‘二‘,‘三‘,‘四‘,‘五‘,‘六‘,‘七‘,‘八‘,‘九‘,‘十‘,‘廿‘);
\$dateStr=‘‘;
if(\$this->ylMonth>10){
\$m2=intval(\$this->ylMonth -10); //十位
\$dateStr=‘十‘.\$tmp[\$m2].‘月‘;
}elseif(\$this->ylMonth==1){
\$dateStr=‘正月‘;
}else{
\$dateStr=\$tmp[\$this->ylMonth].‘月‘;
}

if(\$this->yldate <11){
\$dateStr.=‘初‘.\$tmp[\$this->yldate];
}else{
\$m1=intval(\$this->yldate / 10);
if( \$m1 !=3){
\$dateStr.=(\$m1==1)?‘十‘:‘廿‘;
\$m2=\$this->yldate % 10;
if(\$m2==0){
\$dateStr.=‘十‘;
}else{
\$dateStr.=\$tmp[\$m2];
}
}else{
\$dateStr.=‘三十‘;
}
}
return \$dateStr;
}
/**
*获取该年对于的天干地支年
**/
public function getYGanZhi(){
\$gan=\$this->tianGan[(\$this->ylYeal-4) % 10];
\$zhi=\$this->diZhi[(\$this->ylYeal-4) % 12];
return \$gan.\$zhi.‘年‘;
}
/**
*获取该年对于的天干地支月
**/
public function getMGanZhi(){
\$gan=\$this->tianGan[(\$this->difmonth+3) % 10];
\$zhi=\$this->diZhi[(\$this->difmonth+1) % 12];
return \$gan.\$zhi.‘月‘;
}
/**
*获取该年对于的天干地支日
**/
public function getDGanZhi(){
\$gan=\$this->tianGan[\$this->difDay % 10];
\$zhi=\$this->diZhi[(\$this->difDay+4) % 12];
return \$gan.\$zhi.‘日‘;
}
}
\$c=new Calendar();
\$time=\$c->getLyTime();
trace(date(‘Y-n-j‘).‘对应的农历时间：‘.\$time);

\$c=new Calendar(‘2014-10-1‘);
\$time=\$c->getLyTime();
trace(date(‘Y-n-j‘).‘对应的农历时间：‘.\$time);

function trace(\$info=‘‘){
echo ‘<pre>‘;
print_r(\$info);
echo ‘</pre>‘;
}
``````

********暂时没有添加节假日以及星座等，后期会考虑添加更***

细节相关说明

农历十六进制数据解析

1900年的数据是： 0x04bd8

（如果不想自己推算，在JS里面可以通过`console.log(0x04bd8.toString(2));`来转换）

0000 闰月为小月
0100 1011 1101 1~12个月，每个月包含的天数
1000 代表哪个月为闰月，为0的时候，代表没有闰月

1900~2100年

``````0x04bd8,x04ae0,0x0a570,0x054d5,0x0d260,0x0d950,0x16554,0x056a0,0x09ad0,0x055d2,//1900-1909
0x04970,0x0a4b0,0x0b4b5,0x06a50,0x06d40,0x1ab54,0x02b60,0x09570,0x052f2,0x04970,//1920-1929
0x0d4a0,0x1d8a6,0x0b550,0x056a0,0x1a5b4,0x025d0,0x092d0,0x0d2b2,0x0a950,0x0b557,//1940-1949
0x06ca0,0x0b550,0x15355,0x04da0,0x0a5b0,0x14573,0x052b0,0x0a9a8,0x0e950,0x06aa0,//1950-1959
0x0aea6,0x0ab50,0x04b60,0x0aae4,0x0a570,0x05260,0x0f263,0x0d950,0x05b57,0x056a0,//1960-1969
0x095b0,0x049b0,0x0a974,0x0a4b0,0x0b27a,0x06a50,0x06d40,0x0af46,0x0ab60,0x09570,//1980-1989
0x04af5,0x04970,0x064b0,0x074a3,0x0ea50,0x06b58,0x055c0,0x0ab60,0x096d5,0x092e0,//1990-1999
0x0c960,0x0d954,0x0d4a0,0x0da50,0x07552,0x056a0,0x0abb7,0x025d0,0x092d0,0x0cab5,//2000-2009
0x14b63,0x09370,0x049f8,0x04970,0x064b0,0x168a6,0x0ea50, 0x06b20,0x1a6c4,0x0aae0,//2050-2059
0x0a2e0,0x0d2e3,0x0c960,0x0d557,0x0d4a0,0x0da50,0x05d55,0x056a0,0x0a6d0,0x055d4,//2060-2069
0x0e968,0x0d520,0x0daa0,0x16aa6,0x056d0,0x04ae0,0x0a9d4,0x0a2d0,0x0d150,0x0f252,//2090-2099
0x0d520////2100``````

怎样计算农历y年有多少天

0000 0100 1011 1100 0100，怎样才能分别得到其第5位到第16位上的数字呢？这时候，我们可以通过与运算来实现。让其分别如以下二进制做与运算

0000 1000 0000 0000 0000 ===>0x08000 ==>如果为0，代表第5位上的数字为0，否则为1

0000 0100 0000 0000 0000 ===>0x04000 ==>如果为0，代表第6位上的数字为0，否则为1

0000 0010 0000 0000 0000 ===>0x02000 ==>如果为0，代表第7位上的数字为0，否则为1

********************中间省略********************************

0000 0000 0000 0010 0000 ===>0x00020 ==>如果为0，代表第15位上的数字为0，否则为1

0000 0000 0000 0001 0000 ===>0x00010 ==>如果为0，代表第16位上的数字为0，否则为1

0x08000 ====>0x00010

``````for(\$i=0x8000; \$i>=0x10; \$i>>=1){
\$curNum=0x04bd8 && \$i ? 1 :0;
}``````

``````    /**
*计算农历y年有多少天
**/
public function getYearDays(\$y){
\$sum = 348;//12*29=348,不考虑小月的情况下
for(\$i=0x8000; \$i>=0x10; \$i>>=1){
\$sum += (\$this->dataInfo[\$y-1900] & \$i)? 1: 0;
}
return(\$sum+\$this->leapDays(\$y));
}
/**
*获取某一年闰月的天数
**/
public function leapDays(\$y){
if(\$this->leapMonth(\$y)){
return((\$this->dataInfo[\$y-1900] & 0x10000)? 30: 29);

} else {
return(0);
}
}
/**
*计算哪一月为闰月
*/
public  function leapMonth(\$y){
return (\$this->dataInfo[\$y-1900] & 0xf);
}``````

PHP 32位怎样解决时间戳范围的限制问题

``````var_dump(strtotime(‘1900-1-31‘));  //返回false
var_dump(strtotime(‘2050-3-01‘));//返回false``````

``````\$c1=new DateTime(‘1900-1-31‘, new DateTimeZone(‘PRC‘));
\$c2=new DateTime(‘2111-01-01‘,new DateTimeZone(‘PRC‘));

var_dump(\$c1->format(‘U‘)); //-2206425600
var_dump(\$c2->format(‘U‘));//4449484800``````

【转载ToString()转换格式;DateTime.ToString()用法详解】

ToString()转换格式;DateTime.ToString()用法详解 格式模式 说明和关联属性 c.C 货币格式.关联的属性包括: CurrencyDecimalDigits, CurrencyDecimalSeparator, CurrencyGroupSeparator, CurrencyGroupSizes, CurrencyNegativePattern, CurrencyPositivePattern, CurrencySymbol. d.D 十进制格式. e.E 科学计数(指

什么尼康没有把取景线条设置成九宫格，而是设置成16格，详解

http://forum.xitek.com/thread-1008606-1-1-1.html 看到一个神贴,详细解释了为什么尼康没有吧取景线条设置成九宫格,而是设置成16格.在此,向鹿鸣幽谷 表示感谢.解决我一个大问题. 鹿鸣幽谷 在实时取景中才能显示,取景器内没有.用屏幕实时取景的时候,按快门旁边的 info 键,屏幕会有三种模式(名字都是我起的,就那个意思):信息量少的干净模式.当前拍摄参数显示.分割线模式(代替黄金分割模式).D3100并没有像传统相机那样提供九宫格,当初我也很纳闷,觉

Scala中隐式参数与隐式转换的联合使用实战详解及其在Spark中的应用源码解析之Scala学习笔记-51

package com.leegh.implicits /** * @author Guohui Li */ object Implicit_Conversions_with_Implicit_Parameters { def main(args: Array[String]): Unit = { def bigger[T](a: T, b: T)(implicit ordered: T => Ordered[T]) = if (ordered(a) > b) a else b println