PHP-有没有一种简单的方法可以在两个日期之间循环并填充缺失的值


PHP - Is there a simple way to loop between two dates and fill in missing values?

我有两个日期。假设它们看起来像这样。

$start = 2010/12/24;
$end = 2012/01/05;

我查询数据库以查找这两个日期之间的访问。我找到了一些。然后我填充一个名为stats的数组。

$stats['2010/12/25'] = 50;
$stats['2010/12/31'] = 25;
...

正如你所看到的,还有几天不见了我需要用零值填充缺失的日期我在想这样的事情。(我已经从开始日期和结束日期中提取了天/月/年。

for($y=$start_year; $y <= $end_year; $y++) {
    for($m=$start_month; $m <=$end_month; $m++) {
        for($d=$start_day; $d <= $end_day; $d++) {

这在一年中会很好,但几个月和几天都不起作用。如果开始日期是15号。随后每个月的第1-14天将被错过。我可以有这样的解决方案。。。

for($y=$start_year; $y <= $end_year; $y++) {
    for($m=1; $m <13; $m++) {
         $total_days = cal_days_in_month(CAL_GREGORIAN, $m, $y) + 1;
         for($d=1; $d <= $total_days; $d++) {

然后我需要一堆if语句来确保开始和结束的月份和日期是有效的。

有更好的方法吗?或者这甚至可以在我的mysql查询中完成吗?

只是为了展示PHP的一些更新的间隔处理方法的威力(pgl在他的回答中提到):

$startDate = DateTime::createFromFormat("Y/m/d","2010/12/24",new DateTimeZone("Europe/London"));
$endDate = DateTime::createFromFormat("Y/m/d","2012/01/05",new DateTimeZone("Europe/London"));
$periodInterval = new DateInterval( "P1D" ); // 1-day, though can be more sophisticated rule
$period = new DatePeriod( $startDate, $periodInterval, $endDate );
foreach($period as $date){
   echo $date->format("Y-m-d") , PHP_EOL;
}

是否需要PHP>=5.3.0

编辑

如果您需要包括实际的结束日期,那么您需要在foreach()循环之前向$endDate添加一天:

$endDate->add( $periodInterval );

编辑#2

$startDate = new DateTime("2010/12/24",new DateTimeZone("Europe/London"));
$endDate = new DateTime("2012/01/05",new DateTimeZone("Europe/London"));
do {
   echo $startDate->format("Y-m-d") , PHP_EOL;
   $startDate->modify("+1 day");
} while ($startDate <= $endDate);

对于PHP 5.2.0(或更早版本,如果启用了dateTime对象)

如果您使用的是PHP5.3,那么Mark Baker的答案就是您要使用的答案。如果(正如你在评论中所说)你仍在PHP5.2上,这样的东西应该会对你有所帮助:

$startdate = strtotime( '2010/12/24' );
$enddate = strtotime( '2012/01/05' );
$loopdate = $startdate;
$datesArray = array();
while( $loopdate <= $enddate ) {
   $datesArray[$loopdate] = 0;
   $loopdate = strtotime( '+1 day', $loopdate );
}

它将创建一个unix时间戳数组,其中包含起始日期和结束日期之间的每个日期作为索引,每个值都设置为零。然后,您可以用正确的值覆盖任何实际结果。

$start_date = DateTime::createFromFormat('Y/m/d', '2010/12/24');
$end_date = DateTime::createFromFormat('Y/m/d', '2012/01/05');
$current_date = $start_date;
while($current_date <= $end_date) {
    $current_date = $current_date->add(new DateInterval('P1D'));
    // do your array work here.
}

请参阅DateTime::add()以获取有关此操作的更多信息。

$i = 1;
while(date("Y/m/d", strtotime(date("Y/m/d", strtotime($start)) . "+ $i days")) < $end) {
    ... code here ...
    $i++;
}

我会以天为单位计算开始日期和结束日期之间的差异,并在每次迭代中向时间戳中添加一天。

$start = strtotime("2010/12/24");
$end = strtotime("2012/01/05");
// start and end are seconds, so I convert it to days 
$diff = ($end - $start) / 86400; 
for ($i = 1; $i < $diff; $i++) {
    // just multiply 86400 and add it to $start
    // using strtotime('+1 day' ...) looks nice but is expensive.
    // you could also have a cumulative value, but this was quicker
    // to type
    $date = $start + ($i * 86400); 
    echo date('r', $date);
}

我保存了这段可怕的代码:

while (($tmptime = strtotime('+' . (int) $d++ . ' days', strtotime($from))) && ($tmptime <= strtotime($to)))    // this code makes baby jesus cry
    $dates[strftime('%Y-%m-%d', $tmptime)] = 0;

(将$from$to设置为适当的值。)这可能也会让你哭——但它有点管用。

当然,正确的方法是使用DateInterval