用PHP获取最后三个15天的句号

时间:2016-09-21 21:16:20

标签: php

我无法为此提出解决方案,谷歌似乎没有产生任何东西(我也不确定要搜索什么)但基本上,我想要的是获得最后三个 15天期间。

该月的第1至第15个月和第16个月至该月的最后一天。

我们今天说,我们是在2016年9月22日。我想得到的日期范围是:

Sep 1 - Sep 15
Aug 16 - Aug 31
Aug 1 - Aug 15

同样,如果我们在2016年9月12日,我想要的日期是:

Aug 16 - Aug 31
Aug 1 - Aug 15
Jul 16 - July 31

现在我有一些像这样的伪代码:

  1. 获取日期(编号)
  2. 检查是否大于15
  3. 获取最后15天的日期范围
  4. 继续在此之前再获得2个日期范围
  5. 我想我遇到的问题是将3和4翻译成PHP代码。

    有人可以在这里说清楚吗?

3 个答案:

答案 0 :(得分:1)

我们可以将这些要求简化为两个不同的事情。

  1. 将给定月份定义为2个时段。第一个是本月的第一天到本月的第15天。第二个,是本月最后一天的第16个月。
  2. 在给定日期的情况下,确定从该日期开始的当前期间之后的最后3个期间,独占。
  3. 第1步

    第一部分很简单。

    $date = new DateTimeImmutable("Sep 22, 2016");
    
    // Period 1 (from 1st day of month to 15th)
    $p1Start = $date->modify("first day of this month");
    $p1End   = $p1Start->add(new DateInterval("P14D"));
    
    // Period 2 (from 16th day of month to last day of month)
    $p2Start = $p1End->add(new DateInterval("P1D"));
    $p2End   = $p2Start->modify("last day of this month");
    
    echo "Period 1 Starts On: {$p1Start->format('M j, Y')}\n";
    echo "Period 1 Ends On: {$p1End->format('M j, Y')}\n\n";
    
    echo "Period 2 Starts On: {$p2Start->format('M j, Y')}\n";
    echo "Period 2 Ends On: {$p2End->format('M j, Y')}\n";
    

    你从中获得的输出是预期的:

    Period 1 Starts On: Sep 1, 2016
    Period 1 Ends On: Sep 15, 2016
    
    Period 2 Starts On: Sep 16, 2016
    Period 2 Ends On: Sep 30, 2016
    

    现在你只需要将所有这些放在一个函数中并重用相同的解决方案来进入第2步。

    function getPeriods($dateString) {
        $date = new DateTimeImmutable($dateString);
    
        // Period 1 (from 1st day of month to 15th)
        $p1Start = $date->modify("first day of this month");
        $p1End   = $p1Start->add(new DateInterval("P14D"));
    
        // Period 2 (from 16th day of month to last day of month)
        $p2Start = $p1End->add(new DateInterval("P1D"));
        $p2End   = $p2Start->modify("last day of this month");
    
        return [
            "period1" => ["start" => $p1Start, "end" => $p1End],
            "period2" => ["start" => $p2Start, "end" => $p2End],
        ];
    }
    

    现在让我们假设您从2016年9月12日开始。您可以通过检查此函数的返回值来确定此日期所属的时间段。

    $date = "Sep 12, 2016";
    $periods = getPeriods($date);
    if ($date >= $periods["period1"]["start"] && $date <= $periods["period1"]["end"]) {
        // It's in Period1
    } else {
        // It's in Period2
    }
    

    第2步

    现在让我们稍微修改一下这个功能以简化,以便扩展解决方案。因此,我们将其命名为getPeriod而不是getPeriods,并且只返回给定日期的一个句点。

    function getPeriod($dateString) {
        $periods = [];
        $date = new DateTimeImmutable($dateString);
    
        // Period 1 (from 1st day of month to 15th)
        $p1Start = $date->modify("first day of this month");
        $p1End   = $p1Start->add(new DateInterval("P14D"));
    
        // Period 2 (from 16th day of month to last day of month)
        $p2Start = $p1End->add(new DateInterval("P1D"));
        $p2End   = $p2Start->modify("last day of this month");
    
        // Figure out which period the given date belongs in
        if ($date >= $p1Start && $date <= $p1End) {
            $period = ["start" => $p1Start, "end" => $p1End];
        } else {
            $period = ["start" => $p2Start, "end" => $p2End];
        }
    
        return $period;
    }
    

    因此,为了从此日期获取之前的期间,我们只需采用此函数返回的当前期间的start日期,减去 1天从那里开始,再次将新日期发回给函数,以获得前一个时期。

    同样,要获取 next 期间,只需获取end日期,添加1天,然后将其发送回该函数。

    最终结果

    这是一个例子。

    // We want up to 3 periods previous to this given date's period.
    
    $date = "Sep 12, 2016";
    $periods = [];
    $currentPeriod = getPeriod($date);
    for ($i = 0; $i < 3; $i++) {
        $currentPeriod = $periods[] = getPeriod($currentPeriod["start"]->sub(new DateInterval("P1D"))->format("c"));
    }
    
    // Print out the period dates
    
    $i = 1;
    foreach($periods as $period) {
        echo "Period $i: {$period['start']->format('M j, Y')} - {$period['end']->format('M j, Y')}\n";
        $i++;
    }
    

    输出是你期望的......

    Period 1: Aug 16, 2016 - Aug 31, 2016
    Period 2: Aug 1, 2016 - Aug 15, 2016
    Period 3: Jul 16, 2016 - Jul 31, 2016
    

答案 1 :(得分:1)

function getDateRangesStartingFrom(\Carbon\Carbon $date, $numberOfMonths = 3)
{
    $ranges = [];

    for ($i = 0; $i < $numberOfMonths; $i++)
    {
        $month = [];

        /**
         * Generates the first 01-15 range.
         */
        $rangeOne = \Carbon\Carbon::createFromFormat('Y-m-d', "{$date->year}-{$date->month}-01")->addMonths($i);
        $rangeTwo = (clone $rangeOne)->addDays(14);

        $month[] = [$rangeOne, $rangeTwo];

        /**
         * Generates the second 16-X (depending on the month) range.
         */
        $rangeThree = (clone $rangeTwo)->addDays(1);
        $rangeFour = (clone $rangeTwo)->addDays($rangeOne->daysInMonth - 15);

        $month[] = [$rangeThree, $rangeFour];

        /**
         * We push all the ranges into the global array so we can return it later.
         */
        $ranges[$rangeOne->format('F')] = $month;
    }

    return $ranges;
}

$ranges = getDateRangesStartingFrom(\Carbon\Carbon::createFromFormat('Y-m-d', '2016-09-22'));

var_dump($ranges);

我就是这样做的。

我使用Carbon以便更轻松地处理日期,请查看它!

我创建了一个名为getDateRangesStartingFrom(\Carbon\Carbon $date)的函数,该函数采用一个参数来表示范围从哪个日期(或本月,因为这是我们关心的),范围应该从生成范围开始。

然后我进行$numberOfMonths次迭代循环以开始生成。

首先,我们通过使用开始日期的年份和月份来创建范围的第一部分。然后我添加迭代器索引来表示我们所处的月份。其次,我们创建第二个日期,表示第一个范围的后半部分(1-15)。

之后,我们创建另外两个部分,通过减去我们之前添加的天数来计算月中的天数,以便我们获得该月的剩余天数。

我们将所有这些范围推送到函数范围变量中,并返回结果。

Sherif's answer is good as well但如果您想尝试使用碳,请将其作为替代方案。

答案 2 :(得分:1)

试图找到尽可能简单的代码编写的解决方案。 我在代码中有一些评论。我认为这清楚地说明代码是如何工作的。 检查工作代码here

<?php

// use one of the two examples.
// $now = DateTime::createFromFormat('Y-m-d', '2016-09-12');
$now = new DateTime();

print_r(getPeriods($now));

function getPeriods(DateTime $now)
{
    $currentDay = $now->format('d');

    $dates = []; // Hold all date ranges
    $start = clone $now;
    $end = clone $now;

    if ($currentDay > 15) { // For dates after 15th day of month
        // Starting period is the first day of previous month
        $start->modify('first day of previous month');
        //Ending date is the 15th day of this month
        $end->modify('first day of this month')->modify('14 days');
    } else { // For dates before 15th day of month
        //Starting period is the 16th day of the previous of previous month.
        $start->modify('first day of previous month')
            ->modify('first day of previous month')
            ->modify('15 days');
        //Ending period is the last day of previous month
        $end->modify('last day of previous month');
    }
    $dates[] = $start;
    $i = 2;

    // $c will hold all intermediate dates of periods between
    // $start and $end
    $c = clone $start;
    while ($c < $end) {
        if ($c->format('d') > 15) {
            // if we are in the 16th of the month,
            // give me the last day of the month
            $c->modify('last day of this month');
        } else {
            // give me the 15th day of month
            $c->modify('14 days');
        }
        $dates[] = clone $c; // always clone $c so can not change other references
        if ($i > 0) {
            $c->modify('1 day');
            $dates[] = clone $c;
        }
        $i--;
    }

    return array_chunk($dates, 2);
}