使用PHP计算上一个月的今天

一日,遇到一个问题,求上一个月的今天。 最开始我们使用 strtotime(“-1 month”) 函数求值,发现有一个问题,月长度不一样的月份的计算结果有误。 比如:2011-03-31,得到的结果是2011-03-03。我们先不追究什么问题,先看如何解决问题。 此时,想起PHP中有一个mktime函数,于是自己写了如下代码:

echo date("Y-m-d H:i:s", mktime(date("G", $time), date("i", $time),
 date("s", $time), date("n", $time) - 1, date("j", $time), date("Y", $time)));

当执行时,发现结果和strtotime的结果是一样的。

还是基于这个函数,既然无法直接操作月,那么我们从天入手,得到上一个月,然后再使用date拼接数据。如下代码:

$time = strtotime("2011-03-31");

/**
 * 计算上一个月的今天
 * @param type $time
 * @return type
 */
function last_month_today($time) {
     $last_month_time = mktime(date("G", $time), date("i", $time),
                date("s", $time), date("n", $time), - 1, date("Y", $time));
     return date(date("Y-m", $last_month_time) . "-d H:i:s", $time);
}

echo last_month_today($time);

但是此时又有了另一个问题,不存在2011-02-31这样的日期,怎么办?现在的需求是对于这样的日期显示当月最后一天。 如下代码:

 $time = strtotime("2011-03-31");

/**
 * 计算上一个月的今天,如果上个月没有今天,则返回上一个月的最后一天
 * @param type $time
 * @return type
 */
function last_month_today($time){
    $last_month_time = mktime(date("G", $time), date("i", $time),
                date("s", $time), date("n", $time), 0, date("Y", $time));
    $last_month_t =  date("t", $last_month_time);

    if ($last_month_t < date("j", $time)) {
        return date("Y-m-t H:i:s", $last_month_time);
    }

    return date(date("Y-m", $last_month_time) . "-d", $time);
}

echo last_month_today($time);

这里需要注意一点: date(“Y-m”, $last_month_time) . “-d”这段代码。在写代码的过程中如果写成了 “Y-” . date(“m”, $last_month_time) . “-d” 则在跨年的时间上有问题。 这点还是在写这篇文章时发现的。

除了这种方法,还可以先算出年月日再拼接字符串,这里就是纯粹的字符串操作了。

感触:

  • 一个月不写代码,会手生。
  • 代码写完后请多次review或重构,即使比较简单的代码。

使用PHP计算上一个月的今天》上有14条评论

  1. pAUL gAO

    strtotime(“midnight first day of -1 month”);
    我们以前也遇到过,取月份第一天不正确的问题,用我给你的这个就可以了。
    取对了第一天,剩下的就好办了。

    回复
  2. Deepseath

    我也写了一段,返回给定时间的上月本时刻的Unix时间戳
    function last_month_todaytimestamp($time){
    list($y,$m,$d,$h,$i,$s) = explode(‘-’,date(‘Y-n-j-G-i-s’,$time));//获得给定时间的年月日小时分钟秒
    $m = $m – 1;//上月月份(假定)
    if ( $m == 0 ) {
    //如果给定时间为1月份
    $y = $y – 1;//上月的年份
    $m = 12;//上月月份
    }
    $last_month_days = date(‘t’,mktime($h,$i,$s,$m,1,$y));//上月的天数
    return ($time – $last_month_days * 86400);//当前时间减去上月的描述,返回上个月的“当前时间(小时、分钟、秒)”
    }

    回复
    1. 胖胖 文章作者

      PHP在这里的实现使用的是re2c,关于上月的今天这个问题@gAO 的那个方案很不错,midnight关键字可以将时间设置为午夜。这里可以详细看下官网中的示例:http://cn.php.net/manual/zh/function.strtotime.php

      回复
  3. Pingback引用通告: 你可能不了解的strtotime函数 | PHP源码阅读,PHP设计模式,PHP学习笔记-胖胖的空间

  4. Loay

    /**
    *计算指定日期前N月的日期
    *$time 日期字符串,格式’2011-07-31′
    *$month_length 前几个月
    *返回一个日期字符串,格式’2011-02-28′
    */
    function calLMP($time, $month_length){
    $r = date(‘Y-m-d’,strtotime(‘-’.$month_length.’ month’,strtotime($time)));
    list($ey,$em,$ed) = explode(‘-’,$time);
    list($ry,$rm,$rd) = explode(‘-’,$r);

    //关键就是这里。
    $ml = $em-$rm;
    if($ml==($month_length%12 – 1)||($ml+12)==($month_length%12 – 1)){
    $rm–;
    $rd = 30-$rd;
    $r = $ry.’-’.$rm.’-’.$rd;
    }
    return $r;
    }

    echo calLMP(’2007-11-30′, 9);

    回复
  5. 士元

    我从unix time入手
    function last_month_today(){
    $today = time();
    $_this_month_d = date(“d”,$today);
    $last_month = strtotime(date(“Y-m-1 0:0:0″,$today))-1;
    $_last_month_t = date(“t”,$last_month);
    if($_last_month_t>=$_this_month_d){
    return date(“Y-m-$_this_month_d 0:0:0″,$last_month);
    }else{
    return date(“Y-m-$_last_month_t 0:0:0″,$last_month);
    }
    }

    回复
  6. sam.shi

    function getLastMonthOfToday(){
    //判断上个月是否有今天,如果没有则为上个月最后一天
    if(date(‘n’, strtotime(“-1 month”)) == date(‘n’)){
    $day = date(‘j’, time());
    $result = “-$day day”;
    }else{
    $result = ‘-1 month’;
    }
    return date(‘Y-m-d’, strtotime($result));
    }

    我认为我写的这段代码更好,利于理解,并且纠正年月的能力更强,你觉得呢兄弟?

    回复

胖胖进行回复 取消回复

电子邮件地址不会被公开。 必填项已用*标注


*

您可以使用这些HTML标签和属性: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>