基于频率计算一系列未来日期的算法

时间:2013-11-01 02:06:30

标签: php algorithm date scheduler

我正在制定付款计划程序,根据任意开始日期和一组频率之一(每日,每周,每月等)计划n付款,我正在寻求一般这样做的目的算法。

我试图通过包装频率并根据需要添加一定天数,数周,数月来实施这种蛮力手段。这适用于大多数用途。

失败的地方是任意开始日期是在一个月28日之后,频率在每月和每年之间,特别是对于“每个月的第一个”和“每个月的最后一个”等频率。由于第29天,第30天和第31天没有出现在所有月份,因此添加像date('2013-10-31')->addMonth(1)这样的月份会产生无法预测的结果。与添加date('2014-01-31')->addDays(30)之类的月份一样,由于二月份不必要地缩短,也是如此。

对于这个问题,是否有一般解决方案没有我在任何给定月份移动任何给定频率所需的非常复杂的情况?

PHP的奖励积分,但如果需要我可以翻译。

2 个答案:

答案 0 :(得分:2)

“增加一个月”等等,由于月份长度不同而产生的烦恼确实令人烦恼。

如果您的PHP> = 5.2,则解决方案是DateTime class

虽然使用这个类来获得总控制很简单,但

以下是添加一个月的正确代码的一个版本。

// Variables defining the start date
// Example only - this could be any valid date
$year = '2013';
$month = '01';
$day = '31';

// set to the desired starting date and time
$the_date = new DateTime($year . '-' . $month . '-' . $day);

// Jump to the first day of this month
$the_date->modify("first day of this month");

// add 14 days, so we'll land on the 15th
$the_date->add(new DateInterval("P14D"));

// add 1 month - guaranteed to work!
$the_date->add(new DateInterval("P1M"));

// calculate how many days to add to 15 to get back to the **day** we started with...
// (as an integer, regardless of whether it is a valid day of the current month)
$number_days_to_add_back = intval($day) - 15;

// determine the last day of the month stored in $the_date
$test_last_date = clone $the_date;
$test_last_date->modify("last day of this month");
$day_last = $test_last_date->format('j'); // This provides the day, 01-31

// Test if adding $number_days_to_add_back runs past
// the end of the month; if so, adjust it so it won't run past
// the last day of the month
if (15 + $number_days_to_add_back > intval($day_last)) {
    $number_days_to_add_back = intval($day_last) - 15;
}

// Now make the final adjustment
$the_date->modify("" . $number_days_to_add_back . " day");

// Test it - a month has been added
$test = date_format($the_date, 'Y-m-d');

答案 1 :(得分:0)

首先,您需要定义 希望它如何工作。这是业务逻辑问题,更不用说技术问题了。 “一个月”多久了?你的意思是“一个月”作为大约30天的时间跨度(那么多长时间?)或“+一个月”是指“下个月的同一天”?一旦你定义了“31st + 1个月” 应该如何工作,只需要正确实现它。

我的建议是“+1个月”意味着“em>”将月份数增加一个,保持日期数相同,除非当月不存在,在这种情况下使用最后一天这个月“。可以使用以下内容实现:

$date      = mktime(0, 0, 0, 1, 31);  // midnight Jan 31st
$nextMonth = mktime(0, 0, 0, date('n', $date) + 1, 1, date('Y', $date));  // 1st of next month
$newDate   = mktime(0, 0, 0,
                    date('n', $nextMonth),
                    min(date('t', $nextMonth), date('j', $date)),
                    date('Y', $nextMonth));

它不漂亮,但日期/时间计算很少,特别是如果操作的定义含糊不清。