在php开发过程中我们往往需要实现一个日期加多少天或者多少月后产生一个新的日期,在asp等语言中早期使用的是dateadd方法,php如果要计算几天后还是比较方便的,因为每天86400秒,那么天数乘以86400秒即可,通常我们存储日期用时间戳的话,只要时间戳+86400*天数,再配合date函数即可生成几天后的新日期。
那么如果是1个月后呢,因为我们都知道每个月份的天数是不同的特别还要碰到2月份有29天得闰年,那么我们首先想到的是如下方式来做。
比如存储的是日期格式:2014-7-19
<?php
$date = '2014-7-19';
$datearr = explode('-',$date); //当然也可以使用strtotime转成时间类型再用date获取月份
$newdate = $datearr[0].'-'.$datearr[1]+$n.'-'.$datearr[2]; //这里会产生一个如2014-15-19的日期,当然已经不是一个日期格式
$newdate = date('Y-m-d',strtotime($newdate)); //这时我们会发现日期会错位,没达到我们需要的日期
?>
最终我们采用一个先计算闰年的方式在计算月份,并且把dateadd方法最终封装在tpf框架的date扩展类中,以下提供dateadd的实现方法
const YEAR = 'Y';
const MONTH = 'n';
const DATE = 'Y-m-d';
const DAY = 'j';
const DAY_OF_WEEK = 'w';
/**
* 日期相加,返回新的日期
* @param date $date 被加日期
* @param int $num 加上的数量
* @param enum $interval 加上数量的单位,d为天,m为月,y为年
* @return date
*/
public static function DateAdd($date,$num,$interval='d') {
$_sdate = strtotime($date);
switch($interval) {
case 'd':
return date(self::DATE,($_sdate+$num*86400));
break;
case 'm':
return self::_getMonthAdd($_sdate, $num);
break;
case 'y':
$_year = date(self::YEAR,$_sdate)+$num;
$_month = date(self::MONTH,$_sdate);
$_maxDay = self::_getDayMaxByYearMonth($_year, $_month);
$_day = date(self::DAY,$_sdate);
$_day = $_day>$_maxDay ? $_maxDay : $_day;
return $_year.'-'.$_month.'-'.$_day;
break;
default:
return date(self::DATE,($_sdate+$num*86400));
break;
}
}
/**
* 月相加
* @param int $datestamp
* @param int $num
* @return date
*/
private static function _getMonthAdd($datestamp,$num) {
$_nextMonth = (int) ((date(self::MONTH,$datestamp) + $num) % 12);
$_tmpYear = $_nextMonth ==0 ? ((date(self::MONTH,$datestamp) + $num) / 12 - 1) : (date(self::MONTH,$datestamp) + $num) / 12;
$_nextYear = date(self::YEAR,$datestamp) + floor($_tmpYear);
$_nextMonth = $_nextMonth ==0 ? 12 : $_nextMonth;
$_nextMonthMaxDay = self::_getDayMaxByYearMonth($_nextYear, $_nextMonth);
$_nextMonthDay = date(self::DAY,$datestamp) > $_nextMonthMaxDay ? $_nextMonthMaxDay : date(self::DAY,$datestamp);
return $_nextYear.'-'.$_nextMonth.'-'.$_nextMonthDay;
}
/**
* 根据年月返回当月最大天数
* @param int $year
* @param int $month
* @return int
*/
private static function _getDayMaxByYearMonth($year,$month) {
$_max_month_day = array(31,28,31,30,31,30,31,31,30,31,30,31);
if(self::_isLeapYear($year)) {
$_max_month_day[1] = 29;
}
return $_max_month_day[($month-1) % 12];
}