【问题标题】:How to get previous month and year relative to today, using strtotime and date?如何使用strtotime和日期获取相对于今天的上个月和上年?
【发布时间】:2011-03-30 16:56:05
【问题描述】:

我需要获取相对于当前日期的上个月和年份。

但是,请参阅以下示例。

// Today is 2011-03-30
echo date('Y-m-d', strtotime('last month'));

// Output:
2011-03-02

这种行为是可以理解的(在某种程度上),由于 2 月和 3 月的天数不同,上面示例中的代码是我需要的,但在每个月的 1 日到 28 日之间只能 100% 正确工作。

那么,如何以最优雅的方式获取上个月和年份(想想date("Y-m")),这适用于一年中的每一天?最佳解决方案将基于strtotime 参数解析。

更新。稍微澄清一下要求。

我有一段代码可以获取过去几个月的一些统计数据,但我首先显示上个月的统计数据,然后在需要时加载其他月份。这是预期的目的。所以,在这个月里,我想知道我应该拉到哪个月份,以便加载上个月的统计数据。

我还有一个时区感知的代码(现在不是很重要),它接受strtotime兼容的字符串作为输入(初始化内部日期),然后允许调整日期/时间,也使用strtotime-兼容的字符串。

我知道它可以用几个条件和基本数学来完成,但与此相比,这真的很麻烦,例如(如果它工作正常的话):

echo tz::date('last month')->format('Y-d')

所以,我只需要以前的月份和年份,以 strtotime 兼容的方式。

回答(谢谢@dnagirl):

// Today is 2011-03-30
echo date('Y-m-d', strtotime('first day of last month')); // Output: 2011-02-01

【问题讨论】:

  • 你想要的只是月份和年份?没有一天?
  • 您能否准确说明您想要的输入/输出和预期行为?
  • date("m-Y", strtotime("-1 月"));会解决这个问题
  • @Varshaan 感谢您的评论!请不要通过 cmets 提出解决方案,而是创建一个答案。这样就可以围绕您的答案展开对话,并收集选票。
  • @mr.b 同意并已发布为答案

标签: php date strtotime


【解决方案1】:

看看DateTime 类。它应该正确地进行计算,并且日期格式与strttotime 兼容。比如:

$datestring='2011-03-30 first day of last month';
$dt=date_create($datestring);
echo $dt->format('Y-m'); //2011-02

【讨论】:

  • 另外,我的 tz::date() 函数内部使用 DateTime 对象进行时区或时间调整。
  • @mr.b:很高兴我能帮上忙。您是否在 tz::date() 函数中使用 DateTimeZone 类? ca2.php.net/manual/en/class.datetimezone.php
  • tz 类是 TzDate 类的便捷包装器。请参阅pastebin.com/GzUcvvA0,也许您会发现它很有用。代码应该是不言自明的。 tz 类在这里pastebin.com/8mcRu5qe;但是,它不是独立的,因为我使用的是 Kohana 框架,并且它与它提供的一些其他类绑定在一起。
【解决方案2】:

如果日子本身并不重要,请这样做:

echo date('Y-m-d', strtotime(date('Y-m')." -1 month"));

【讨论】:

  • 今天,仍然是三月。我预计是二月。
  • @codecraft 然后尝试这样: echo date('Y-m-d', strtotime(date('Y-m-d')." -1 month"));
  • 对我来说,这两行都给了我 2011-03-02。很奇怪。
  • 该死的 >
  • @Codecraft "-1 月" 和 "-1 月" 我都试过了,它们产生了不同的答案,连字符起作用前的空格:D
【解决方案3】:

我找到了答案,因为我今天遇到了同样的问题,即 31 日。这不是一些人建议的bug in php,而是预期的功能(在某些情况下)。根据post,strtotime 实际所做的是将月份设置回一并且不修改天数。因此,如果是今天,5 月 31 日,它正在寻找 4 月至 31 日,这是一个无效的日期。因此,它需要 4 月 30 日,然后再增加 1 天,并产生 5 月 1 日。

在您的示例 2011-03-30 中,它将返回一个月至 2 月 30 日,这是无效的,因为 2 月只有 28 天。然后取那几天的差 (30-28 = 2),然后在 2 月 28 日(即 3 月 2 日)之后移动两天。

正如其他人所指出的,获取“上个月”的最佳方法是使用 strtotime 或 DateTime 对象添加“第一天”或“最后一天”:

// Today being 2012-05-31
//All the following return 2012-04-30
echo date('Y-m-d', strtotime("last day of -1 month"));
echo date('Y-m-d', strtotime("last day of last month"));
echo date_create("last day of -1 month")->format('Y-m-d'); 

// All the following return 2012-04-01
echo date('Y-m-d', strtotime("first day of -1 month")); 
echo date('Y-m-d', strtotime("first day of last month"));
echo date_create("first day of -1 month")->format('Y-m-d');

因此,如果您进行查询等,使用这些可以创建日期范围。

【讨论】:

    【解决方案4】:

    如果您想要相对于特定日期的上一年和上个月并且有可用的 DateTime,那么您可以这样做:

    $d = new \DateTimeImmutable('2013-01-01', new \DateTimeZone('UTC')); 
    $firstDay = $d->modify('first day of previous month');
    $year = $firstDay->format('Y'); //2012
    $month = $firstDay->format('m'); //12
    

    【讨论】:

    • 这对我来说是一个更好的解决方案。虽然我建议在修改它之前克隆$d,因为这将完全改变$d 的值,因为它是TimeDate 对象。 $d2 = clone $d 然后在$d2 上调用modify() 就像$d2->modify('first day of previous month') 这样$d$d2 保持不同。
    • @AllanDereal 在这种情况下 DateTimeImmutable 更合适
    【解决方案5】:
    date('Y-m', strtotime('first day of last month'));
    

    【讨论】:

    • 这是完美的。通过使用第一天,它可以防止像 2 月 31 日、6 月 31 日等这样的事情。
    【解决方案6】:

    strtotime 有第二个timestamp 参数,使第一个参数相对于第二个参数。所以你可以这样做:

    date('Y-m', strtotime('-1 month', time()))
    

    【讨论】:

    • 真的很好很短的代码,mysql有没有相同的选项?即: CURDATE()-$day //30 但如果当前月份为 31 天,则不返回真正的月份。
    【解决方案7】:

    如果我正确地理解了你上个月和它所在年份的问题:

    <?php
    
      $month = date('m');
      $year = date('Y');
      $last_month = $month-1%12;
      echo ($last_month==0?($year-1):$year)."-".($last_month==0?'12':$last_month);
    
    ?>
    

    示例如下:http://codepad.org/c99nVKG8

    【讨论】:

      【解决方案8】:

      嗯,它不是一个人提到的错误。这是预期的行为,因为一个月中的天数通常不同。使用 strtotime 获取上个月的最简单方法可能是从本月的第一天开始使用 -1 个月。

      $date_string = date('Y-m', strtotime('-1 month', strtotime(date('Y-m-01'))));
      

      【讨论】:

      • 抛开编程不谈,如果我今天(2011 年 3 月 30 日)在街上拦住你,问你上个月的这个时间是什么时候 - 并且你必须给出答案,你会诚实地回答“ 3 月 3 日”?我不会!
      • @Codecraft:也许正确的答案是“没有那个时候”,因为真的没有“这个时候,一个月前”。但是一个月前确实有这个时间,它只是取决于“一个月前”的定义。我想这整个问题都是由这个定义引起的。
      • @dqhendricks:我没有提到具体日期,是吗? :) 另外,有趣的选择天数 - strtotime 是如何得出我想减去 2 月份的天数的结论的?为什么没有当月的天数?很奇怪。
      • @mr.b 也许自从我们上个月问起,它算出上个月有多少天,并减去它们哈哈。如果减去这个月的天数,就会出现其他类型的错误。从三月开始减去一个月将返回一月的日期。
      【解决方案9】:

      我认为您在 strtotime 函数中发现了一个错误。每当我必须解决这个问题时,我总是发现自己在计算月/年值。试试这样的:

      $LastMonth = (date('n') - 1) % 12;
      $Year      =  date('Y') - !$LastMonth;
      

      【讨论】:

      • 怎么不是bug?一个月是一个没有上下文的定义不明确的单位,该函数缺乏对它的上下文支持。
      【解决方案10】:
      date("m-Y", strtotime("-1 months")); 
      

      会解决这个问题的

      【讨论】:

        【解决方案11】:

        也许比你想的要冗长一些,但我使用的代码可能比必要的要多,以使其更具可读性。

        也就是说,它得出的结果与您得到的结果相同 - 您想要/期望它得出什么结果?

        //Today is whenever I want it to be.
        $today = mktime(0,0,0,3,31,2011);
        
        $hour   = date("H",$today);
        $minute = date("i",$today);
        $second = date("s",$today);
        $month  = date("m",$today);
        $day    = date("d",$today);
        $year   = date("Y",$today);
        
        echo "Today: ".date('Y-m-d', $today)."<br/>";
        echo "Recalulated: ".date("Y-m-d",mktime($hour,$minute,$second,$month-1,$day,$year));
        

        如果您只想要月份和年份,那么只需将日期设置为“01”而不是“今天”:

         $day = 1;
        

        这应该可以满足您的需求。您可以将小时、分钟和秒设置为零以及您对使用它们不感兴趣。

         date("Y-m",mktime(0,0,0,$month-1,1,$year);
        

        减少了很多;-)

        【讨论】:

        • 其实,这真的很有趣。我希望并希望这段代码在 2 月 28 日或 3 月 1 日产生,但绝对不是 3 月 3 日!我叫虫子!
        • 好吧,我认为这完全取决于您的期望。这就是为什么我一直小心翼翼地不把它称为一个错误,因为它可能是期望的 功能。如果我在 3 月 31 日询问date('Y-m-d', strtotime('last month')),它应该返回哪个日期?二月的最后一天?我不太确定..也许在该领域有更多经验的人可以阐明为什么 strtotime 的行为方式是这样的..
        • 你说得对,对我来说,它的行为很奇怪,但我想这是可能没有“正确”答案的问题之一。
        【解决方案12】:

        这是因为上个月的天数少于当前月份。我已通过首先检查上个月的天数是否少于当前天数并根据它更改计算来解决此问题。

        如果天数较少,则获取 -1 个月的最后一天,否则获取当前日期 -1 个月:

        if (date('d') > date('d', strtotime('last day of -1 month')))
        {
            $first_end = date('Y-m-d', strtotime('last day of -1 month'));
        }
        else
        {
            $first_end = date('Y-m-d', strtotime('-1 month'));
        }
        

        【讨论】:

          【解决方案13】:

          如果可以接受 DateTime 解决方案,则此 sn-p 返回上个月的年份和上个月的月份,避免在一月份运行时可能出现的陷阱。

          function fn_LastMonthYearNumber()
          {
           $now = new DateTime();
           $lastMonth = $now->sub(new DateInterval('P1M'));
           $lm= $lastMonth->format('m');
           $ly= $lastMonth->format('Y');
           return array($lm,$ly);
          }
          

          【讨论】:

          【解决方案14】:
          //return timestamp, use to format month, year as per requirement
          function getMonthYear($beforeMonth = '') {
              if($beforeMonth !="" && $beforeMonth >= 1) {
                  $date = date('Y')."-".date('m')."-15";
                  $timestamp_before = strtotime( $date . ' -'.$beforeMonth.' month' );
                  return $timestamp_before;
              } else {
                  $time= time();
                  return $time;
              }
          }
          
          
          //call function
          $month_year = date("Y-m",getMonthYear(1));// last month before  current month
          $month_year = date("Y-m",getMonthYear(2)); // second last month before current month
          

          【讨论】:

            【解决方案15】:
            function getOnemonthBefore($date){
                $day = intval(date("t", strtotime("$date")));//get the last day of the month
                $month_date = date("y-m-d",strtotime("$date -$day days"));//get the day 1 month before
                return $month_date;
            }
            

            结果日期取决于输入月份的天数。如果输入月份是2月(28天),那么2月5日之前的28天就是1月8日。如果输入的是5月17日,那么之前的31天就是4月16日。同样,如果输入的是5月31日,那么结果日期就是4月30日。

            注意:输入需要完整的日期('y-m-d')和输出('y-m-d'),您可以修改此代码以满足您的需要。

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2023-01-31
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2018-10-10
              • 1970-01-01
              相关资源
              最近更新 更多