首页 > 解决方案 > Given start date and period: Find start date of current period

问题描述

Each customer has their individual contract start date (YYYY-MM-DD) and billing period (full calendar months).

Given any current day, I want to find the date the current billing period has started.

Some examples:

| Start date | Billing period | Current date | Start of current period |
|----------------------------------------------------------------------|
| 2018-01-01 | 12 Months      | 2020-09-25   | 2020-01-01              |
| 2018-01-01 | 6 Months       | 2020-09-25   | 2020-07-01              |
| 2018-01-01 | 18 Months      | 2020-09-25   | 2019-07-01              |
| 2018-01-01 | 13 Months      | 2020-09-25   | 2020-03-01              |

My naive approach would be to start adding periods to the start date until the resulting date is bigger than the current date. Then take the date before that iteration. However, I don’t like this, since with ongoing time the loop would take longer and longer.

标签: algorithmdate

解决方案


The basic idea is to divide the passed months from contract start to now through the period length. The remainder represents the number of months we’re into the current period. So subtract that remainder from the current month and we should end up with the starting month of the period we’re in.

This is how I solved it for now (written in PHP):

public function getStartDateOfCurrentPeriod(DateTime $contractStart, int $periodLength) : DateTime
{
    $now = new DateTime();

    $start = [
        'year' => intval($contractStart->format('Y')),
        'month' => intval($contractStart->format('m')),
        'day' => intval($contractStart->format('d'))
    ];

    $now = [
        'year' => intval($now->format('Y')),
        'month' => intval($now->format('m')),
        'day' => intval($now->format('d'))
    ];

    if ($start['day'] > $now['day']) {
        $now['month'] -= 1;

        if ($now['month'] <= 0) {
            $now['year'] -= 1;
            $now['month'] += 12;
        }
    }

    $start['months'] = $start['year'] * 12 + $start['month'];
    $now['months'] = $now['year'] * 12 + $now['month'];

    $monthsPassed = $now['months'] - $start['months'];

    $usedFromPeriod = $monthsPassed - floor($monthsPassed / $periodLength) * $periodLength;

    $yearDelta = floor($usedFromPeriod / 12);
    $monthDelta = $usedFromPeriod - $yearDelta * 12;

    $periodStart = [
        'year' => $now['year'] -  $yearDelta,
        'month' => $now['month'] - $monthDelta,
        'day' => $start['day']
    ];

    if ($periodStart['month'] <= 0) {
        $periodStart['year'] -= 1;
        $periodStart['month'] += 12;
    }

    return new DateTime(sprintf('%u-%u-%u', $periodStart['year'], $periodStart['month'], $periodStart['day']));
}

推荐阅读