PHP将两个相互冲突的日期范围组合成唯一的对
第一组:PHP将两个相互冲突的日期范围组合成唯一的对,php,date,date-range,Php,Date,Date Range,第一组: 2014-04-05至2014-06-27 2014-06-28至2014-10-19 第二组: 2014-04-05至2014-05-02 2014-05-03至2014-05-31 2014-06-01至2014-10-19 我需要输出的是: 2014-04-05至2014-05-02 2014-05-03至2014-05-31 2014-06-01至2014-06-27 2014-06-28至2014-10-19 我尝试使用一个函数来检查重叠: !($lhs['RecordOns
!($lhs['RecordOnset'] > $rhs['RecordOffset'] || $lhs['RecordOffset'] < $rhs['RecordOnset'])
第二对将是一个单独的数组,因为它可能具有相同的密钥
在此方面的任何指导或帮助都将不胜感激。PHP的日期范围在线资源非常有限。以下是我的解决方案:
<?php
$array1 = array(
array('s'=>'2014-04-05','e'=>'2014-06-27'),
array('s'=>'2014-06-28','e'=>'2014-10-19')
);
$array2 = array(
array('s'=>'2014-04-05','e'=>'2014-05-02'),
array('s'=>'2014-05-03','e'=>'2014-05-31'),
array('s'=>'2014-06-01','e'=>'2014-10-19')
);
//merge arrays together
$merged_array = array_merge($array1,$array2);
//filter out duplicate start dates
$filtered_array = array();
foreach($merged_array as $k=>$v){
if(!isset($filtered_array[ $v['s'] ] )){
$filtered_array[ $v['s'] ] = $v;
}
//if the end date is before the currently saved end date (for this start date) then use it
if( strtotime($v['e']) < strtotime($filtered_array[ $v['s'] ]['e']) ){
$filtered_array[ $v['s'] ] = $v;
}
}
//reset the array to zero based
$filtered_array = array_values($filtered_array);
//sort the array by start date
$tmp = array();
foreach($filtered_array as $k=>$v){
$tmp[$k] = $v['s'];
}
array_multisort($tmp,SORT_ASC,$filtered_array);
//end date overlap checking
foreach($filtered_array as $k=>$v){
//if the end date is after (or equal to) the "next" start date, then make that end date the "yesterday" of the next start date
if( isset($filtered_array[$k+1]['s']) && strtotime($v['e']) >= strtotime($filtered_array[$k+1]['s']) ){
$yesterday = strtotime($filtered_array[$k+1]['s']) - 1;
$yesterday = date("Y-m-d",$yesterday);
$filtered_array[$k]['e'] = $yesterday;
}
}
echo '<pre>',print_r($filtered_array),'</pre>';
/*
Array
(
[0] => Array
(
[s] => 2014-04-05
[e] => 2014-05-02
)
[1] => Array
(
[s] => 2014-05-03
[e] => 2014-05-31
)
[2] => Array
(
[s] => 2014-06-01
[e] => 2014-06-27
)
[3] => Array
(
[s] => 2014-06-28
[e] => 2014-10-19
)
)
*/
准备
嗯。现在我们需要循环数组$start
:对于每个start
查找比start
更接近的end
。做它:
$ranges[$end] = $start;
你需要什么
注意
关于循环中的这一行:
$ranges[$end] = $start;
我们可以有这样的情况:
$input = [
// One day.
(object) [
'title' => 'One day.',
'from' => 1560816000,
'to' => 1560902399,
],
// Same day, inner period
(object) [
'title' => 'Same day, inner period',
'from' => 1560816000 + 1000,
'to' => 1560902399 - 1000,
],
// Just before midnight
(object) [
'title' => 'Just before midnight',
'from' => 1560816000 - 1000,
'to' => 1560816000 + 1000,
],
// Just after midnight
(object) [
'title' => 'Just after midnight',
'from' => 1560902399 - 1000,
'to' => 1560902399 + 1000,
],
// Other period before
(object) [
'title' => 'Other period before',
'from' => 1560902399 - 100000,
'to' => 1560902399 - 100000 + 5000,
],
// Other period after
(object) [
'title' => 'Other period after',
'from' => 1560816000 + 100000,
'to' => 1560902399 + 100000 + 5000,
],
];
但这是错误的。只需要最后一个范围2014-04-05至2014-05-02
。和行:
Array
(
[0] => Array
(
[from] => 2019-06-17 22:13:19
[to] => 2019-06-17 23:36:39
)
[1] => Array
(
[from] => 2019-06-18 01:43:20
[to] => 2019-06-19 02:16:39
)
[2] => Array
(
[from] => 2019-06-19 05:46:40
[to] => 2019-06-20 07:09:59
)
)
使用相同键=>的覆盖值最终将设置为正确的2014-04-05
键2014-05-02
用法:$output=mergeRanges($input)代码>
该方法最初设计用于合并数值范围内的任何类型,包括时间戳,并支持任何类型的重叠。它接受输入中的对象数组,其中包含可自定义的“from”和“to”键
/**
*@param$范围
*@param string$keyFrom
*@param string$keyTo
*
*@return数组
*/
函数mergeRanges($ranges,$keyFrom='from',$keyTo='to')
{
//从/到值拆分。
$arrayFrom=[];
$arrayTo=[];
foreach($范围为$日期)
{
$arrayFrom[]=$date->$keyFrom;
$arrayTo[]=$date->$keyTo;
}
//分类ASC。
natsort($arrayFrom);
纳索特($arrayTo);
$ranges=[];
//迭代开始日期。
foreach($arrayFrom作为$indexFrom=>$from)
{
//获取以前的条目。
$previousEntry=结束($ranges);
//查找关联的默认“to”值到“from”值。
$to=$arrayTo[$indexFrom];
//如果我们有以前的条目且“to”大于
//当前“从”值。
如果(设置($previousEntry->to)&&$from<$previousEntry->to+1)
{
//如果此范围完全覆盖,则不执行任何操作
//由上一个。
如果($to>$previousEntry->to)
{
//我们只需将te“改为”先前范围的值,
//所以我们不创建新条目。
$previousEntry->to=$to;
}
}
其他的
{
//创建一个新的范围条目。
$ranges[]=(对象)[
$keyFrom=>$from,
$keyTo=>$to,
];
}
}
返回$ranges;
}
例如:
结果:
这个范围是一个字符串,两个独立的日期/时间戳,你如何接收这些数据,。。??将数组或w/e中的数据添加到您的问题中。我使用的是数组中的日期格式。。例如,第一组是:数组(数组('start'=>'04/05/2014','end'=>'2014-06-27'),数组('start'=>'2014-06-28','end'=>'2014-10-19')),您希望找到两个数组中可用的所有时间段,对吗?比如说,如果你只知道两个人假期的开始和结束,你就可以试着找出他们何时可以见面?这就是我试图做的一个很好的例子。使用范围,保持时间框架的唯一性。。就像日历一样,查找两个人有约会的时间以及他们在约会之外的空闲时间。非常感谢您的输入。到目前为止,这看起来不错,我正在尝试测试这一点。到目前为止,当我返回结果时(在原始数组中有更多开始和结束的数据),日期不是从最小到最大的顺序。我的解决方案可能并不完美,但希望它能为您指明正确的方向array\u multisort()
应允许您根据开始日期使用阵列。我将致力于实现此解决方案,因为它易于理解和理解。你能解释一下最后一部分的意思吗--$ranges[$end]=$start。我想我没有听你的解释。@Nick McCaly你可以更改$ranges[$end]=$start代码>到行$ranges[]=array('start'=>$start,'end'=>$end)
;。如果您这样做了=>还需要删除“combine”
循环。然后你就可以明白为什么我会选择$ranges[$end]=$start不,我现在完全明白你的意思了。非常感谢您对全文的详细解释。这也是一种简单的处理方法。。有时我们都有脑放屁
$ranges = array();
foreach($starts as $start){
$start_time = strtotime($start);
foreach($ends as $end){
$end_time = strtotime($end);
if ($start_time>$end_time) continue;
else{
$ranges[$end] = $start;
break;
}
}
}
// "combine"
$result = array();
foreach($ranges as $end=>$start) {
$result[] = array('start' => $start, 'end' => $end);
}
// print final result
foreach($result as $item){
echo $item['start'].' To '.$item['end'].'<br/>';
}
2014-04-05 To 2014-05-02
2014-05-03 To 2014-05-31
2014-06-01 To 2014-06-27
2014-06-28 To 2014-10-19
$ranges[$end] = $start;
2014-04-03 To 2014-05-02
2014-04-04 To 2014-05-02
2014-04-05 To 2014-05-02
$ranges[$end] = $start;
$input = [
// One day.
(object) [
'title' => 'One day.',
'from' => 1560816000,
'to' => 1560902399,
],
// Same day, inner period
(object) [
'title' => 'Same day, inner period',
'from' => 1560816000 + 1000,
'to' => 1560902399 - 1000,
],
// Just before midnight
(object) [
'title' => 'Just before midnight',
'from' => 1560816000 - 1000,
'to' => 1560816000 + 1000,
],
// Just after midnight
(object) [
'title' => 'Just after midnight',
'from' => 1560902399 - 1000,
'to' => 1560902399 + 1000,
],
// Other period before
(object) [
'title' => 'Other period before',
'from' => 1560902399 - 100000,
'to' => 1560902399 - 100000 + 5000,
],
// Other period after
(object) [
'title' => 'Other period after',
'from' => 1560816000 + 100000,
'to' => 1560902399 + 100000 + 5000,
],
];
Array
(
[0] => Array
(
[from] => 2019-06-17 22:13:19
[to] => 2019-06-17 23:36:39
)
[1] => Array
(
[from] => 2019-06-18 01:43:20
[to] => 2019-06-19 02:16:39
)
[2] => Array
(
[from] => 2019-06-19 05:46:40
[to] => 2019-06-20 07:09:59
)
)