【问题标题】:Set next month payment date (with PHP Carbon)设置下个月的付款日期(使用 PHP Carbon)
【发布时间】:2020-12-23 18:26:53
【问题描述】:

我需要确定下个月的付款日期。所以我选择最后一个截止日期 并增加一个月。我该怎么做?

我的例子是:最后一次付款是 1 月 31 日,我正在做

Carbon::create(2018, 1, 31, 0, 0, 0)->addMonthsNoOverflow(1)

它有效,它提供2018-02-28,但之后下一次付款将在 28 日再次到期。所以我需要在添加一个月后设置一个日期。

Carbon::create(2018, 2, 28, 0, 0, 0)->addMonthsNoOverflow(1)->day(31)

它给了我2018-03-31,这很好,但如果我在第一个例子中使用这个公式

Carbon::create(2018, 1, 31, 0, 0, 0)->addMonthsNoOverflow(1)->day(31)

它让我溢出2018-03-03。这是我的问题。我应该怎么办?有没有类似->setDayNoOverflow(31) 的东西?

【问题讨论】:

  • 哦,这很棘手。您可以使用->endOfMonth() 作为您的示例,但我仍然建议您将月份计为 30 天。添加简单,计算简单,您和客户都无需费脑筋:)
  • 我希望我有权做出这样的决定。
  • @JohnConde,谢谢。回答的真好,这里也可以用。

标签: php laravel php-carbon


【解决方案1】:

您不应使用最后付款日期,而应保留第一个日期并从第一个日期开始计算所有其他日期,而不是前一个日期:

Carbon::create(2018, 1, 31, 0, 0, 0)
Carbon::create(2018, 1, 31, 0, 0, 0)->addMonthsNoOverflow(1)
Carbon::create(2018, 1, 31, 0, 0, 0)->addMonthsNoOverflow(2)
Carbon::create(2018, 1, 31, 0, 0, 0)->addMonthsNoOverflow(3)

假设您没有这些数据,您仍然可以:

$day = 31;
$date = Carbon::create(2018, 1, 28, 0, 0, 0);
$date->addMonthsNoOverflow(1);
$date->day(min($day, $date->daysInMonth));

【讨论】:

  • 谢谢。我不需要月底,我需要设定一个日期。可能是第 20 次,在这种情况下,我的第一个想法会奏效,可能是第 30 次,在这种情况下,我的第一个和第二个想法以及您的想法都会失败。
  • 好的,明白了,你已经迭代了多次,所以这里你需要从初始日期开始(并添加2、3、4个月......),而不是从上一个日期开始添加。
  • 好主意。如果我不要求使用以前的截止日期和日期作为输入参数,它就会得到答案。我的问题是 - 如果有人没有及时付款但后来付款,他应该根据之前的成功付款日期获得一个新的到期日。
  • 所以我推荐$date->day(min($day, $date->daysInMonth))查看我的最后编辑。
【解决方案2】:

好像Carbon中没有这个功能,为什么不自己做呢?

public function setDaysNoOverflow($value)
    {
        $year = $this->year;
        $month = $this->month;

        $this->day((int)$value);

        if ($month !== $this->month) {
            $this->year = $year;
            $this->month = $month;
            $this->modify('last day of this month');
        }

        return $this;
    }

只需将其添加到 Carbon/Carbon.php 即可。

它基于addMonthsNoOverflow函数源。

警告:未经测试,仅供参考。

【讨论】:

  • 你可能也想减去一个月
  • 哦,当然,错过了
  • 这是对 Carbon 的拉取请求:github.com/briannesbitt/Carbon/pull/1387
  • 我认为@KyleK 提供了更好的解决方案。我希望没有难过的感觉。
  • 这是你的决定,我同意。尽管如此,我还是玩得很开心:)
【解决方案3】:

我认为这里的实际问题是关于业务逻辑或数据库架构,而不是日期操作。

尽管我不确定您的订阅模式是什么,但您似乎想跟踪两条不同的信息:

  • 服务付费的截止日期,
  • 付款到期日。

如果尝试将两者都存储在一个字段中,您可能会丢失一些信息,就像 1 月/2 月/3 月转换的情况一样。通过使用单独的字段,您可以阻止它并建立每个月的付款到期日,例如 KyleK 提出的:

$lastPayment->addMonthsNoOverflow(1)->day(
    min($paymentDue->day, $lastPayment->daysInMonth)
);

在我看来,这样做有点复杂,可以通过以下方式大大简化:

  1. 使用营业月(30 天)而不是日历月,
  2. 放弃最初的付款日期,只在最后一次付款的基础上增加一个月。

但我知道这可能不是由您决定的。

【讨论】:

    【解决方案4】:

    您可以将其用作循环

        // from month
        $min = 3;
        // to mont
        $max = 9;
        // all dates
        $paymentDates = [];
        $date2 = \Carbon\Carbon::now();
        // next day (or today)
        $day = $date2->addDay(1)->format('d');
        $currentMonth = $date2->format('m');
        $year = $date2->format('Y');;
        
        $date = \Carbon\Carbon::now();
    
        $nextMonth = $currentMonth;
    
        for($i = $min; $i <= $max; $i++) {
          $date = \Carbon\Carbon::create($year, $currentMonth, $day)->addMonthsNoOverflow($nextMonth)->format('d/m/Y');
          // add to array
          array_push($paymentDates, $date);
          // next month
          $nextMonth++;
        }
    

    【讨论】:

      【解决方案5】:

      您可以使用 Carbon 库中提供的 addMonth() 函数,如下所示

      Carbon::create(2018, 1, 31, 0, 0, 0)->addMonth();
      

      【讨论】:

      • 我希望这个 2018-02-28 是下一个付款日期。但我不会用你的公式得到它。
      猜你喜欢
      • 2016-11-22
      • 2012-07-16
      • 1970-01-01
      • 2021-10-20
      • 1970-01-01
      • 2016-09-09
      • 1970-01-01
      • 2016-09-01
      • 2013-06-24
      相关资源
      最近更新 更多