algorithm - 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.
解决方案
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']));
}
推荐阅读
- javascript - Google 脚本字符串以 ... 结尾,然后未定义
- c - C结构故障?(我是 C 编程新手)
- angular - 带片段的子路线
- javascript - 用 setInterval 改变 useState 的值
- javascript - 如何将标记添加到图层并使用传单显示它们
- reactjs - 过渡动画在 tailwindcss/react 中不起作用
- sonos - Sonos Api:有没有办法了解 Sonos 最喜欢玩的是哪个?
- unreal-engine4 - 如果不重新启动,虚幻引擎将无法启动到 Oculus Quest 2
- python - 一个类必须实现所有抽象方法吗?
- angular - Angular 10 表单动作没有变化