简体   繁体   English

PHP获得明年同一周的同一天

[英]PHP get same day of same week next year

I'm working on a client scheduler and my employer wants it to automatically reschedule clients each year. 我正在研究客户调度程序,我的雇主希望它每年自动重新安排客户。 He wants them to keep the same day of the same week every year. 他希望他们每年保持同一周的同一天。

For example, a client is scheduled for May 23rd 2014. This is the fourth friday of may. 例如,客户定于2014年5月23日。这是5月的第四个周五。 Once May 23rd 2014 has passed, a appointment for the fourth friday of may in 2015 should be booked (in this case the 22nd). 2014年5月23日过后,应预订2015年5月4日的预约(在本案例中为第22次)。

I've tried various things to get this to work (such as using DateTime to advance by a year and find "previous" of whatever day of the week it was). 我已经尝试了各种各样的工作来使这个工作(例如使用DateTime提前一年,并找到一周中任何一天的“之前”)。 But every model I've tried breaks down a bit after just a few years. 但是,我尝试过的每一款车型在短短几年后都会出现故障。 They'll end up on like...the second Friday of the month. 他们最终会像......这个月的第二个星期五。

Does anyone have a way to get this to work? 有没有人有办法让这个工作? My employer is very specific about wanting the scheduler to work this way. 我的雇主非常具体地希望调度程序以这种方式工作。 xx I'd really appreciate the help if someone knows how. xx如果有人知道如何,我真的很感激帮助。

Thanks for reading this! 感谢您阅读本文!

As has already been pointed out, there may not be a 5th Friday in June, for example, so there needs to be some standard way to decide which week next year is the same week as the current one. 正如已经指出的那样,例如,可能没有6月的第5个星期五,所以需要一些标准的方法来决定明年哪一周与当前星期相同。

As it happens there is already a standard for week numbering in ISO 8601 and PHP's DateTime class has built in functionality for handling them. 实际上, ISO 8601中已有一个用于周编号的标准 ,PHP的DateTime类内置了处理它们的功能。

My suggestion would be to schedule the next meeting for the same day in the same ISO 8601 week number the following year. 我的建议是安排同一天的下一次会议在同一年的ISO 8601 week number The following function will do that for you:- 以下功能将为您完成: -

/**
 * @param \DateTime $date Date of the original meeting
 * @return \DateTime Date of the next meeting
 */
function getSameDayNextYear(\DateTime $date = null)
{
    if(!$date){
        $date = new \DateTime();
    }
    return (new \DateTime())->setISODate((int)$date->format('o') + 1, (int)$date->format('W'), (int)$date->format('N'));
}

See it working with some test code . 看到它使用一些测试代码

I'm sure you'll agree that this is the simplest way of doing it and it should see you right for the next 100 years or more :) 我相信你会同意这是最简单的方法,它会让你在接下来的100年或更长时间内正确行事:)

References DateTime and Date for formats. 参考日期时间日期的格式。

I think this will do what you need. 我认为这将满足您的需求。 You'll need to thoroughly test it out to be sure, though. 不过,你需要彻底测试它才能确定。

$event = new DateTime('2014-05-18');
$dayOfWeek = $event->format('l');
if ($dayOfWeek !== 'Sunday') {
    $event->modify('previous Sunday'); 
}
else {
    $event->modify('-1 day'); 
}
$event->modify('+1 year');
if ($dayOfWeek !== 'Sunday' && $dayOfWeek !== $event->format('l')) {
    $event->modify('next ' . $dayOfWeek);
}
echo $event->format('Y-m-d');

Demo 演示

So changing your requirements to "add a year and find the next matching day of the week" I've come up with this: 因此,将您的要求更改为“添加一年并找到一周的下一个匹配日期”,我想出了这个:

function nextDate($date = false){
    if(!$date){ $date = new DateTime(); }
    $oneYear = new DateInterval('P1Y');
    $dayOfWeek = $date->format('w');
    $nextDate = clone $date;
    $nextDate->add($oneYear);
    $nextYearDayOfWeek = $nextDate->format('w');
    while($nextYearDayOfWeek != $dayOfWeek){
        // add a day and check again
        $nextDate->add(new DateInterval('P1D'));
        $nextYearDayOfWeek = $nextDate->format('w');
    }
    return $nextDate;
}

And my tests: 我的测试:

$test1 = new DateTime('5/23/2014');
$test2 = new DateTime('5/24/2014');
$test3 = new DateTime('5/25/2014');
$test4 = new DateTime('5/26/2014');
$test5 = new DateTime('5/27/2014');
$test6 = new DateTime('5/28/2014');
$test7 = new DateTime('5/29/2014');
$test8 = new DateTime('1/1/2014');
$test9 = new DateTime('12/31/2014');
$test10 = new DateTime('5/5/2040');

$nextDate1 = nextDate($test1);
$nextDate2 = nextDate($test2);
$nextDate3 = nextDate($test3);
$nextDate4 = nextDate($test4);
$nextDate5 = nextDate($test5);
$nextDate6 = nextDate($test6);
$nextDate7 = nextDate($test7);
$nextDate8 = nextDate($test8);
$nextDate9 = nextDate($test9);
$nextDate10 = nextDate($test10);

print($nextDate1->format('m/d/y'));
print('<br />');
print($nextDate2->format('m/d/y'));
print('<br />');
print($nextDate3->format('m/d/y'));
print('<br />');
print($nextDate4->format('m/d/y'));
print('<br />');
print($nextDate5->format('m/d/y'));
print('<br />');
print($nextDate6->format('m/d/y'));
print('<br />');
print($nextDate7->format('m/d/y'));
print('<br />');
print($nextDate8->format('m/d/y'));
print('<br />');
print($nextDate9->format('m/d/y'));
print('<br />');
print($nextDate10->format('m/d/y'));

Results: 结果:

05/29/15
05/30/15
05/31/15
06/01/15
06/02/15
06/03/15
06/04/15
01/07/15
01/06/16
05/11/41

Edit 编辑

I've modified the function below to find the closest day of the week instead of the next one (though it tends to just be the same as the previous one except subtracting). 我已经修改了下面的函数来找到一周中最接近的一天而不是下一个(虽然它除了减去之外它往往与前一个相同)。

function nextDate($date = false){
    if(!$date){ $date = new DateTime(); }
    $oneYear = new DateInterval('P1Y');
    $dayOfWeek = $date->format('w');
    $nextDate = clone $date;
    $nextDate->add($oneYear);
    $nextYearDayOfWeek = $nextDate->format('w');
    $diff = $dayOfWeek-$nextYearDayOfWeek;
    // if $diff is more than 3, it's faster to go the other way
    if(abs($diff) > 3){
        if($diff > 0){
            $diff = $diff-7;
        }else{
            $diff = 7+$diff;
        }
    }

    if($diff != 0){
        if($diff < 0){
            $nextDate->sub(new DateInterval('P'.abs($diff).'D'));
        }else{
            $nextDate->add(new DateInterval('P'.$diff.'D'));
        }
    }

    return $nextDate;
}

Test results this time: 这次测试结果:

05/22/15
05/23/15
05/24/15
05/25/15
05/26/15
05/27/15
05/28/15
12/31/14
12/30/15
05/04/41

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM