设置下个月的付款日期(使用 PHP Carbon)

Set next month payment date (with PHP Carbon)

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

我的示例是:最后一次付款是 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) 的东西?

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::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));

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

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

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

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

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

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

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

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

  1. 使用工作月(30 天)而不是日历月,
  2. 放弃原来的付款日,只在最后一次付款后增加一个月。

不过据我所知,这可能不由您决定。

您可以将其用作循环

    // 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++;
    }