Algorithm for calculating a series of future dates based on a frequency [closed]

假如想象 提交于 2019-12-06 12:01:53

The "add a month", etc., annoyance due to different month lengths is, indeed, irritating.

The solution, if you have PHP >= 5.2, is the DateTime class.

Though it is simple to use this class to obtain total control, it is not entirely trivial.

Here is one version of correct code to add a month.

// 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');

First and foremost you need to define how you want it to work. This is a business logic problem, much less a technical problem. How long is "one month"? Do you mean "one month" as a time span of roughly 30 days (how long exactly then?) or does "+ one month" mean "same day next month"? Once you have defined how "31st + 1 month" should work, it's simply a matter of implementing it correctly.

My suggestion would be that "+1 month" means "increase the month number by one, keeping the day number the same, unless the day does not exist in the month, in which case use the last day of the month". Which can be implemented using something like this:

$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));

It ain't pretty, but date/time calculations rarely are, especially if the definition of the operation is vague.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!