我想我仍然会遇到这个问题,所以希望您能给我一些解决方法。
我正在开发一个应用程序,使您可以大致了解您的定期付款(我知道,这笔钱已经存在,这只是一个附带项目)和您的支出。
API即将完成,但是我在本节中苦苦挣扎:我需要知道是否需要在给定的时间范围内重复付款。
重复发生的事件(合同)除其他字段外还包含startDate,endDate,intervalType(枚举[每周,每月,每季度,每半年,每年])
当前,我将其作为学说查询:
return $this->createQueryBuilder('e')
->andWhere('e.startDate >= :start')
->andWhere('e.endDate <= :end')
->andWhere('e.user = :user')
->setParameter('start', $start)
->setParameter('end', $end)
->setParameter('user', $user)
->getQuery()
->getResult();
其中参数start和end是间隔的帧。
但是我如何检查所选框架内合同的到期时间和频率?
Afaik只有通过遍历查询结果并检查合同是否与时间表相交,并注意该合同在此期间发生的频率和时间,才有可能实现。
但是我不知道该怎么做。
示例数据:
[name, intervalType, startDate, endDate, amount]
rent, monthly, 2019-01-01, 2020-10-11, -500
utility, monthly, 2019-01-01, 2020-10-11, -150
salary, monthly, 2019-01-01, 2020-10-11, 1700
investment, biannually, 2019-02-10, null , 2500
food, weekly, 2019-01-01, null , -50
如果我有本月的时间表(2019-05-01-2019-05-31),我将获得这些合同:
rent 2019-05-01
utility 2019-05-01
salary 2019-05-01
food 2019-05-01
food 2019-05-08
food 2019-05-15
food 2019-05-22
food 2019-05-29
如果我选择以下两个月(2019-07-01-2019-08-31),我会得到这个:
rent 2019-07-01
rent 2019-08-01
utility 2019-07-01
utility 2019-08-01
salary 2019-07-01
salary 2019-08-01
food 2019-07-01
food 2019-07-08
food 2019-07-15
food 2019-07-22
food 2019-07-29
food 2019-08-01
food 2019-08-08
food 2019-08-15
food 2019-08-22
food 2019-08-29
investment 2019-08-01
使用DateTime和DateInterval可以吗?
答案 0 :(得分:0)
每周间隔的逻辑对我来说似乎是错误的。至少使用我的银行应用程序,每周计划始终会在同一工作日进行,两次连续两次之间要间隔7天。
因此,按照这种逻辑,您可以使用此功能:
function getScheduleBetween($data, $intervalStart, $intervalEnd) {
$ref = [
"yearly" => [12, "months"],
"annually" => [12, "months"],
"biannually" => [6, "months"],
"quarterly" => [3, "months"],
"monthly" => [1, "months"],
"weekly" => [7, "days"],
"daily" => [1, "days"]
];
$intervalStart = new DateTime($intervalStart);
$intervalEnd = new DateTime($intervalEnd);
$result = [];
foreach($data as $schedule) {
// Convert start/end to DateTime
$startDate = new DateTime($schedule["startDate"]);
$endDate = $schedule["endDate"] ? min(new DateTime($schedule["endDate"]), $intervalEnd) : $intervalEnd;
$name = $schedule["name"];
$interval = $schedule["intervalType"];
if (!isset($ref[$interval])) throw "Invalid interval type";
list($coeff, $interval) = $ref[$interval];
$match = clone $startDate;
if ($match < $intervalStart) {
$diff = $intervalStart->diff($match);
$count = $interval == "days" ? $diff->format("%a") : $diff->m + $diff->y * 12 + ($diff->d ? 1 : 0);
$count = ceil($count / $coeff) * $coeff;
$match->modify("+$count $interval");
}
while ($match <= $endDate) {
$temp = clone $match;
$result[] = ["name" => $name, "date" => $temp->format("Y-m-d")];
$match->modify("+$coeff $interval");
}
}
array_multisort(array_column($result, "date"), $result);
return $result;
}
示例用法:
$data = [
["name" => "rent", "intervalType" => "monthly", "startDate" => "2019-01-01", "endDate" => "2020-10-11", "amount" => -500],
["name" => "utility", "intervalType" => "monthly", "startDate" => "2019-01-01", "endDate" => "2020-10-11", "amount" => -150],
["name" => "salary", "intervalType" => "monthly", "startDate" => "2019-01-01", "endDate" => "2020-10-11", "amount" => 1700],
["name" => "investment", "intervalType" => "biannually", "startDate" => "2019-02-10", "endDate" => null, "amount" => 2500],
["name" => "food", "intervalType" => "weekly", "startDate" => "2019-01-01", "endDate" => null, "amount" => -50],
];
$result = getScheduleBetween($data, "2019-05-01", "2019-05-31");
print_r($result);
周期较大:
$result = getScheduleBetween($data, "2019-05-01", "2019-08-31");
print_r($result);
如果您有其他类型的时间间隔,我相信即使使用“每周”的其他逻辑,您也可以轻松扩展此功能以支持它们。