检查一个集合内的连续日期并返回范围 [英] Check for consecutive dates within a set and return as range

查看:84
本文介绍了检查一个集合内的连续日期并返回范围的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个数组的日期Y-m-d格式,可以是一天中的十个设置日期的任意组合。



例如以下是全集:



2011-01-01,2011-01-02,2011-01-03,2011-01-04,2011-01-05 ,2011-01-06,2011-01-07,2011-01-08,2011-01-09,2011-01-10



创建的数组从这个集合可以是任何组合的日期 - 所有这些,其中一个,一些连续,所有连续等。



我目前有他们打印几乎,因为他们回来了例如这是一个可能的结果:



2011-01-02



2011-01-03



2011-01-04



2011-01-08



(实际打印的内容更像1月2日星期五...,但我们会坚持简单的日期字符串)



我想缩小它,如果连续三天甚至更长,那么这些范围就会变成:



2011-01-02至2011-01-04



2011-01-08



最终将成为:



1月2日 - 1月4日星期二

1月8日星期六



有没有办法循环并检查时差,创建范围的开始时间和结束时间,然后收集stragglers?

解决方案

一个快速答案的位置对于缺乏实现感到抱歉,但假设哟你使用5.3,日期按时间顺序排列,你可以将每个日期转换为一个 DateTime 对象(如果它们还没有),然后使用 DateTime :: diff() 生成一个 DateInterval 对象,您可以使用它来比较迭代中的当前日期与最后一个。您可以将您的连续日期分组到子数组中,并使用 shift() pop()获取第一个和最后一个



编辑



我想过这个。相当粗糙和准备好的实现遵循,但它应该工作:

  //假设按时间顺序
//有序数组DateTime对象

$ dates = array(
new DateTime('2010-12-30'),
new DateTime('2011-01-01'),
new DateTime('2011-01-02'),
new DateTime('2011-01-03'),
new DateTime('2011-01-06'),
new DateTime('2011-01-07'),
new DateTime('2011-01-10'),
);

//处理数组

$ lastDate = null;
$ ranges = array();
$ currentRange = array();

foreach($ dates as $ date){

if(null === $ lastDate){
$ currentRange [] = $ date;
} else {

//获取DateInterval对象
$ interval = $ date-> diff($ lastDate);

// DateInterval具有
//天,周的属性。几个月等你应该
//在这里实现一些更强大的条件到
//确保所有你没有得到假匹配
//的差异像一个月和一天,一个年和
//一天等等...

if($ interval-> days === 1){
//将此日期添加到当前范围
$ currentRange [] = $ date;
} else {
//存储旧范围并重新开始
$ ranges [] = $ currentRange;
$ currentRange = array($ date);
}
}

//迭代结束...
//此日期现在是最后一个日期
$ lastDate = $ date;
}

// messy ...
$ ranges [] = $ currentRange;

//打印日期

foreach($ ranges as $ range){

//总是有一个数组元素,所以
//将该关闭并从日期对象创建一个字符串
$ startDate = array_shift($ range);
$ str = sprintf('%s',$ startDate-> format('D j M'));

//如果$ range
//中仍然有元素,那么这是一个范围。弹出最后一个
//元素,做如上所述并连接
if(count($ range)){
$ endDate = array_pop($ range);
$ str。= sprintf('to%s',$ endDate-> format('D j M'));
}

echo< p> $ str< / p>;
}

输出:

  Thu 30 Dec 
星期六1月至1月3日1月
6月6日至5月7日1月
Mon 10 Jan


I have arrays of dates Y-m-d format that may be any combination of ten set dates that are one day apart.

e.g. Here is the full set:

2011-01-01, 2011-01-02, 2011-01-03, 2011-01-04, 2011-01-05, 2011-01-06, 2011-01-07, 2011-01-08, 2011-01-09, 2011-01-10

The arrays that are created from that set can be any combination of dates— all of them, one of them, some consecutive, all consecutive, etc.

I currently have them printing pretty much as they're returned. e.g. here's a possible result:

2011-01-02

2011-01-03

2011-01-04

2011-01-08

(what's actually printed is more like "Friday, Jan. 2…", but we'll stick with the simple date string)

I'd like to condense it so that if there are three or more consecutive days, those become a range, e.g the above example would become:

2011-01-02 to 2011-01-04

2011-01-08

which would eventually become:

Sunday, Jan. 2 - Tuesday, Jan. 4

Saturday Jan. 8

Is there a way to loop through and check the time difference, create a start time and end time for the range(s), and then gather up the stragglers?

解决方案

Bit of a quick answer so sorry about the lack of implementation but assuming you are using 5.3 and the dates are ordered chronologically, you could convert each date to a DateTime object (if they aren't already) and then iterate over the array using DateTime::diff() to generate a DateInterval object which you could use to compare the current date in the iteration with the last. You could group your consecutive dates into sub arrays and use shift() and pop() to get the first and last days in that sub array.

EDIT

I had a think about this. Pretty rough and ready implementation follows, but it should work:

// assuming a chronologically
// ordered array of DateTime objects 

$dates = array(
    new DateTime('2010-12-30'), 
    new DateTime('2011-01-01'), 
    new DateTime('2011-01-02'), 
    new DateTime('2011-01-03'), 
    new DateTime('2011-01-06'), 
    new DateTime('2011-01-07'), 
    new DateTime('2011-01-10'),
);

// process the array

$lastDate = null;
$ranges = array();
$currentRange = array();

foreach ($dates as $date) {    

    if (null === $lastDate) {
        $currentRange[] = $date;
    } else {

        // get the DateInterval object
        $interval = $date->diff($lastDate);

        // DateInterval has properties for 
        // days, weeks. months etc. You should 
        // implement some more robust conditions here to 
        // make sure all you're not getting false matches
        // for diffs like a month and a day, a year and 
        // a day and so on...

        if ($interval->days === 1) {
            // add this date to the current range
            $currentRange[] = $date;    
        } else {
            // store the old range and start anew
            $ranges[] = $currentRange;
            $currentRange = array($date);
        }
    }

    // end of iteration... 
    // this date is now the last date     
    $lastDate = $date;
}

// messy... 
$ranges[] = $currentRange;

// print dates

foreach ($ranges as $range) {

    // there'll always be one array element, so 
    // shift that off and create a string from the date object 
    $startDate = array_shift($range);
    $str = sprintf('%s', $startDate->format('D j M'));

    // if there are still elements in $range
    // then this is a range. pop off the last 
    // element, do the same as above and concatenate
    if (count($range)) {
        $endDate = array_pop($range);
        $str .= sprintf(' to %s', $endDate->format('D j M'));
    }

    echo "<p>$str</p>";
}

Outputs:

Thu 30 Dec
Sat 1 Jan to Mon 3 Jan
Thu 6 Jan to Fri 7 Jan
Mon 10 Jan

这篇关于检查一个集合内的连续日期并返回范围的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆