php计算农历日期
因为项目是面向海外的,所以调用网上判断节假日的接口是没用的,最后决定只判断春节与国庆节。
我的想法是通过判断农历日期来单独判断春节,如果有更好的办法欢迎大神指点哈。
下面贴代码(这个类是很早之前在网上看到一个前辈写的,原帖找不到了)
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("子","丑","寅","卯","辰","巳","午","未","申","酉","戌","亥");
private $dataInfo=array(0x04bd8,0x04ae0,0x0a570,0x054d5,0x0d260,0x0d950,0x16554,0x056a0,0x09ad0,0x055d2,//1900-1909
0x04ae0,0x0a5b6,0x0a4d0,0x0d250,0x1d255,0x0b540,0x0d6a0,0x0ada2,0x095b0,0x14977,//1910-1919
0x04970,0x0a4b0,0x0b4b5,0x06a50,0x06d40,0x1ab54,0x02b60,0x09570,0x052f2,0x04970,//1920-1929
0x06566,0x0d4a0,0x0ea50,0x06e95,0x05ad0,0x02b60,0x186e3,0x092e0,0x1c8d7,0x0c950,//1930-1939
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
0x096d0,0x04dd5,0x04ad0,0x0a4d0,0x0d4d4,0x0d250,0x0d558,0x0b540,0x0b6a0,0x195a6,//1970-1979
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
0x0a950,0x0b4a0,0x0baa4,0x0ad50,0x055d9,0x04ba0,0x0a5b0,0x15176,0x052b0,0x0a930,//2010-2019
0x07954,0x06aa0,0x0ad50,0x05b52,0x04b60,0x0a6e6,0x0a4e0,0x0d260,0x0ea65,0x0d530,//2020-2029
0x05aa0,0x076a3,0x096d0,0x04bd7,0x04ad0,0x0a4d0,0x1d0b6,0x0d250,0x0d520,0x0dd45,//2030-2039
0x0b5a0,0x056d0,0x055b2,0x049b0,0x0a577,0x0a4b0,0x0aa50,0x1b255,0x06d20,0x0ada0,//2040-2049
0x14b63,0x09370,0x049f8,0x04970,0x064b0,0x168a6,0x0ea50, 0x06b20,0x1a6c4,0x0aae0,//2050-2059
0x0a2e0,0x0d2e3,0x0c960,0x0d557,0x0d4a0,0x0da50,0x05d55,0x056a0,0x0a6d0,0x055d4,//2060-2069
0x052d0,0x0a9b8,0x0a950,0x0b4a0,0x0b6a6,0x0ad50,0x055a0,0x0aba4,0x0a5b0,0x052b0,//2070-2079
0x0b273,0x06930,0x07337,0x06aa0,0x0ad50,0x14b55,0x04b60,0x0a570,0x054e4,0x0d160,//2080-2089
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();
//这个是我很low判断,哈哈
if($time == '正月初一' || $time == '正月初二' || $time == '正月初三' || $time == '正月初四' || $time == '正月初五' || $time == '正月初六' || $time == '正月初七' ||
('1001'<= $date && $date <= '1007') ){
return '1';//放假
}else{
return '0';//不放假
}