获取日期间隔内的重复日期

时间:2019-05-06 13:34:17

标签: php date time

我想我仍然会遇到这个问题,所以希望您能给我一些解决方法。

我正在开发一个应用程序,使您可以大致了解您的定期付款(我知道,这笔钱已经存在,这只是一个附带项目)和您的支出。

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可以吗?

1 个答案:

答案 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);

如果您有其他类型的时间间隔,我相信即使使用“每周”的其他逻辑,您也可以轻松扩展此功能以支持它们。