生成人类可读的(非)后续日期列表


Generate human readable list of (non)-subsequent dates

当给定一个n个日期的列表时,可以是后续日期只是普通的随机日期;生成适当的人类可读字符串的最佳方法是什么。

我举个例子:

2016-02-13, 2016-02-14, 2016-02-15, 2016-02-16

应表示为:

feb 13th '16 - feb 16th '16

将日期转换为人类可读的对应项很容易;我对某种算法感兴趣,可以将日期数组减少到尽可能短的解决方案。

当列表包含"漏洞"时,事情开始变得困难:

2016-02-13, 2016-02-14, 2016-02-15, 2016-03-02, 2016-03-03
feb 13th '16 - feb 15th '16 & mar 2nd '16 - mar 3rd '16

我已经为此打破了一段时间;我没有进一步打破列表,排序它,让它独一无二,看看中间有多少天,然后检查一下有多少元素。

但是解决"漏洞"问题更难...而且我的解决方案不是水密的。

关于如何处理这个问题的任何想法?

写得很匆忙,所以请仔细检查,尤其是夏令时的情况。主要思想是我们需要获取间隔:

<?php
  date_default_timezone_set('UTC');
  $dates=explode(', ',
  '2015-02-13, 2015-02-14, 2015-02-15, 2015-02-16, 2016-02-13, 2016-02-14, 2016-02-15, 2016-03-02, 2016-03-03');
  $intervals = Array();
  $t0 = -1;
  $t = $t0;
  if(count($dates))
    foreach($dates as $d)
    {
      $t00 = strtotime("$d -1 day");
      if($t != $t00)
      {
        if($t0 != -1)
        {
          if($t == $t0)
            $intervals[]=date("M jS 'y",$t0);
          else
            $intervals[]=date("M jS 'y",$t0) . ' - ' . date("M jS 'y",$t);
        }
        $t = strtotime($d);
        $t0 = $t;
      }
      else
        $t = strtotime($d);
    }
  if ($t0 != $t)
    $intervals[]=date("M jS 'y",$t0) . ' - ' . date("M jS 'y",$t);
  echo join(" & ", $intervals);

结果:

Feb 13th '15 - Feb 16th '15 & Feb 13th '16 - Feb 15th '16 & Mar 2nd '16 - Mar 3rd '16

在@kay27的帮助下,引入了搜索间隔的想法,这就是我现在创建间隔列表的方式。假设这是一个雄辩模型中的方法,$this->data .并使用碳来制作漂亮的日期修饰符。

public function fd($format = 'Y-m-d')
{
    $dates = [];
    $intervals = [];
    foreach ($this->data as $d) {
        $dates[] = 'Carbon::parse($d->datum);
    }
    // sort the dates..

    // init
    $i=0;
    $t=0;
    $peil = $dates[$i];
    $intervals[$t] = [$peil];
    // loop through the dates starting from 0+1, as we already
    // 'processed' the first entry.
    for ($i=1; $i < count($dates); $i++) {
        //  when not equal; then we will need to create a new inTerval,
        //  so we increase the index:
        if ($peil != $dates[$i]->copy()->subDay()) {
            $t++;
        }
        // adding the date to the appropriate interval.
        $intervals[$t][] = $dates[$i];
        // the reference date, as-in the last date added to the list.
        $peil = $dates[$i];
    }

    // do some formatting on the intervals
    return $intervals;
}