做PHP万年历的最大困难有两个方面:一是mktime()函数的局限,二是Windows平台下Windows对合法时间的规定。
PHP函数mktime()用以获取UNIX时间戳记,即从UNIX时代创建以来到指定时间的总秒数,其意义是为date()等函数处理时间信息提供一个可解析的时间数据。UNIX时代从1970年1月1日开始,因此理论上mktime()能够返回的有效数据只适用于1970年以后的年份。
比起UNIX时间系统,Windows则显得小气了,它的合法时间系统更为狭小。如若PHP运行于Windows平台,mktime()函数还得看Windows的脸色。在UNIX和Linux操作环境下,date()通过mktime()读取1970年以前某个日期的时间戳记总是能够返回一个值(虽然不正确),而获取2038年以后的时间戳记,Windows平台下date()也会报错。
上述问题不解决,PHP万年历就名不副实。解决的思路之一是:绕开date()和mktime()函数,即,不使用它们参与处理日历的核心内容。
这需要对阳历进行必要的研究,深入掌握其内在规律。
阳历经历了三个时代:儒略历、奥古斯都历和现在仍然通行的格里历(又称格列高利历)。格里历由罗马教皇格列高利十三世于1582年10月15日(原奥古斯都历的10月5日,这一天不存在)倡导使用,直至今日。我们现在做万年历就是基于格里历的日历,即,做万年历要考虑的因素是格里历的规律。往下我们讨论的“阳历”指的就是格里历。
阳历有如下几个规则:
一. 一年的总天数:平年365天,闰年366天;
二. 闰年:非世纪年的年份(即不被100整除的年份)被4整除的为闰年,世纪年的年份(即被100整除的年份)被400整除的年份为闰年。闰年的二月份有29天;
三. 月份天数:
1. 大月(31天):一月、三月、五月、七月、八月、十月、十二月;
2. 小月(30天):四月、六月、九月、十一月;
3. 二月为28天,闰年为29天。
这些规律足以让我们抛开PHP的时间日期函数,取而代之的是使用我们根据格里历规律编写的自定义函数。
首先判断处理年(y年)是否为闰年,这将关系到处理年的总天数和二月的总天数:
function is_yleap($y) { //是否闰年: 返回1(代表闰年)或0(非闰年)
return($y%100==0 ? $result=($y%400==0 ? 1 : 0) : $result=($y%4==0 ? 1 : 0));
}
能够判断任意年是否为闰年之后,我们就可以计算处理年的总天数:
function y_days($y) { //y年的总天数
return($total=365+is_yleap($y));
}
以及处理年的各月的总天数:
function m_days($y,$m) { //y年m月的总天数
switch($m) {
case 1:
case 3:
case 5:
case 7:
case 8:
case 10:
case 12:
$total=31;
break;
case 4:
case 6:
case 9:
case 11:
$total=30;
break;
case 2:
$total=28+is_yleap($y);
break;
}
return $total;
}
现在还剩下一个写日历更为核心的问题:判断每个月的第一天是星期几。这个问题必须解决,否则,日历每月的一日写在哪里无从确定。
我们可以使用著名的蔡勒(Zeller)公式来求得y年m月n日是星期几。以下是经数模原理简化过的蔡勒公式:
W = [C/4]-2C+y+[y/4]+[13*(M+1)/5]+d-1 ... mod(7)
y为年份数(二位),C为世纪数(二位),m为月份数,d为日期数。求出W值后对7取模(即求余数)将得到从0到6的值,依次代表从周日到周六。这个公式不必考虑闰年因素,但要求:一、1月和2月视为13月和14月,同时年份减去1,减去后若世纪数受影响,则按影响后的变化取值;二、中括号里的算式仅取计算结果的整数部分,小数点后的值忽略不计。
根据蔡勒公式,我们可以很方便地判断处理年(y年)处理月(m月)第一天是星期几:
function wk1day($y,$m) { //当月第一天周几
if($m<3) { //一月和二月按上一年的13月和14月取值
$y-=1;
if($m==1) $m=13;
if($m==2) $m=14;
}
$c=substr($y,0,2);
$yy=substr($y,2,2);
$cal=floor($c/4) - 2*$c + $yy + floor($yy/4) + floor(13*($m+1)/5);
return ($cal+700)%7;
}
至此,绕开UNIX和Windows时间限制制作万年历的条件已经具备,理论上它的有效性可以从1582年10月15日起到4049年。4049年以后,由于地球自转等因素,阳历日期与太阳回归年将出现较大的误差,届时格里历如果还使用的话将面临着调整。
php关于1970年前日期的处理
http://blog.csdn.net/fzhlee/archive/2010/07/27/5769049.aspx
我在处理一篇会员注册页面时,客户要求日期从1960年开始,这样就会产生以下问题:
Warning : date() [function.date ]: Windows does not support dates prior to midnight (00:00:00), January 1, 1970 in c:\program files\wamp\www\friends\admin\users_manager.php on line 320
Warning : date() [function.date ]: Windows does not support dates prior to midnight (00:00:00), January 1, 1970 in c:\program files\wamp\www\friends\admin\users_manager.php on line 321
Warning : date() [function.date ]: Windows does not support dates prior to midnight (00:00:00), January 1, 1970 in c:\program files\wamp\www\friends\admin\users_manager.php on line 322
在网上搜了半天,没找到合适的办法,于是千思万想,想到了以下的办法,解决了这个问题:
本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/fzhlee/archive/2010/07/27/5769049.aspx