Tengo 2 fechas en PHP, ¿cómo puedo ejecutar un bucle foreach para pasar por todos esos días?

207

Estoy empezando con una cita 2010-05-01y terminando con 2010-05-10. ¿Cómo puedo recorrer todas esas fechas en PHP?

Shamoon
fuente

Respuestas:

535

Requiere PHP5.3:

$begin = new DateTime('2010-05-01');
$end = new DateTime('2010-05-10');

$interval = DateInterval::createFromDateString('1 day');
$period = new DatePeriod($begin, $interval, $end);

foreach ($period as $dt) {
    echo $dt->format("l Y-m-d H:i:s\n");
}

Esto generará todos los días en el período definido entre $starty $end. Si desea incluir el 10, establezca el $end11. Puede ajustar el formato a su gusto. Consulte el Manual de PHP para DatePeriod .

Gordon
fuente
2
Buenas noticias: hay un parche para configurar una bandera para incluir la fecha de finalización que (con los dedos cruzados) la convertirá en una versión futura.
salathe
8
$begin->setTime(0,0); $end->setTime(12,0);o inicializar con la hora del día de la fecha de inicio, ya que cualquier momento posterior a la fecha de finalización incluirá la fecha de finalización en el bucle. No es la solución más elegante, pero es la mejor opción siempre que no haya una bandera adecuada.
Chris
31
Si desea incluir la fecha de finalización en su intervalo, puede hacer: $ end = $ end-> modificar ('+1 día');
JulienITARD
3
¿Es posible usar esto pero revertirlo para retroceder en la historia?
Jon
3
@JulienITARD es una buena idea, pero más elegante sería $ end-> add ($ intervalo) porque responde directamente a un intervalo cambiado;)
GDY
92

Esto también incluye la última fecha

$begin = new DateTime( "2015-07-03" );
$end   = new DateTime( "2015-07-09" );

for($i = $begin; $i <= $end; $i->modify('+1 day')){
    echo $i->format("Y-m-d");
}

Si no necesita la última fecha, simplemente retírela =de la afección.

Sabri Aziri
fuente
1
Asegúrese de tener en cuenta que $beginserá diferente después del ciclo. Este bucle modifica el objeto creado por new DateTime( "2015-07-03" ). Por lo tanto, por qué debería usar las versiones DateTimeImmutable. Pero necesita algunas modificaciones adicionales para usarlos.
Henk Poley
40

La conversión a marcas de tiempo de Unix facilita las matemáticas de fecha en php:

$startTime = strtotime( '2010-05-01 12:00' );
$endTime = strtotime( '2010-05-10 12:00' );

// Loop between timestamps, 24 hours at a time
for ( $i = $startTime; $i <= $endTime; $i = $i + 86400 ) {
  $thisDate = date( 'Y-m-d', $i ); // 2010-05-01, 2010-05-02, etc
}

Cuando use PHP con una zona horaria con horario de verano, asegúrese de agregar una hora que no sea las 23:00, 00:00 o 1:00 para protegerse contra los días que se saltan o repiten.

Harold1983-
fuente
44
No me gusta el aspecto de ese 86400. Entiendo que es 60 * 60 * 24, pero aún así ... algo me molesta.
MikeD
13
en este caso, funciona, pero si hay un interruptor entre el tiempo normal y la luz solar ahorro, se producirá un error porque hay un segundo día 90000 que tendrá dos veces en su bucle ...
oezi
2
Mike, lo mejor que puedes hacer es configurar una constante y nombrarla "DÍA" para que sea mucho más fácil de leer.
The Pixel Developer
55
Esto sufrirá problemas de horario de verano. Cuando cruzas un punto de horario de verano, se arruinará. 12:00 am no son 12:00 am en ambos lados del punto en el tiempo.
Eric Cope
1
¡Este código tiene (cada código con 86400 segundos por día) tiene problemas con el horario de verano! Con el horario de verano, algunos días duran solo 23 horas y unas 25 horas.
sbrbot
20

Copie de la muestra php.net para el rango inclusivo :

$begin = new DateTime( '2012-08-01' );
$end = new DateTime( '2012-08-31' );
$end = $end->modify( '+1 day' ); 

$interval = new DateInterval('P1D');
$daterange = new DatePeriod($begin, $interval ,$end);

foreach($daterange as $date){
    echo $date->format("Ymd") . "<br>";
}
Alexander Kharchenko
fuente
Esta es la mejor y más completa respuesta. Solo falta alguna explicación del valor de DateInterval P1D, así que aquí hay algunos ejemplos de Designador de período Dos días: P2D Dos segundos: PT2S Una semana y diez minutos: P1WT10M Y por años M por meses D por días W por semanas. Estos se convierten en días, por lo que no se pueden combinar con D. H por horas M por minutos S por segundos
Orcra
15
$startTime = strtotime('2010-05-01'); 
$endTime = strtotime('2010-05-10'); 

// Loop between timestamps, 1 day at a time 
$i = 1;
do {
   $newTime = strtotime('+'.$i++.' days',$startTime); 
   echo $newTime;
} while ($newTime < $endTime);

o

$startTime = strtotime('2010-05-01'); 
$endTime = strtotime('2010-05-10'); 

// Loop between timestamps, 1 day at a time 
do {
   $startTime = strtotime('+1 day',$startTime); 
   echo $startTime;
} while ($startTime < $endTime);
Mark Baker
fuente
2
Parece que esta solución es más lenta que la respuesta aceptada (sin ejecutar algunos bancos: 100% más lento para 60 iteraciones). Pero elegí este por compatibilidad retro para plataformas de alojamiento antiguas.
Si no
7

Aquí hay otro simple:

/**
 * Date range
 *
 * @param $first
 * @param $last
 * @param string $step
 * @param string $format
 * @return array
 */
function dateRange( $first, $last, $step = '+1 day', $format = 'Y-m-d' ) {
    $dates = [];
    $current = strtotime( $first );
    $last = strtotime( $last );

    while( $current <= $last ) {

        $dates[] = date( $format, $current );
        $current = strtotime( $step, $current );
    }

    return $dates;
}

Ejemplo:

print_r( dateRange( '2010-07-26', '2010-08-05') );

Array (
    [0] => 2010-07-26
    [1] => 2010-07-27
    [2] => 2010-07-28
    [3] => 2010-07-29
    [4] => 2010-07-30
    [5] => 2010-07-31
    [6] => 2010-08-01
    [7] => 2010-08-02
    [8] => 2010-08-03
    [9] => 2010-08-04
    [10] => 2010-08-05
)
Hadi
fuente
5

Usuario esta función: -

function dateRange($first, $last, $step = '+1 day', $format = 'Y-m-d' ) {
                $dates = array();
                $current = strtotime($first);
                $last = strtotime($last);

                while( $current <= $last ) {    
                    $dates[] = date($format, $current);
                    $current = strtotime($step, $current);
                }
                return $dates;
        }

Uso / llamada de función: -

Incrementar en un día: -

dateRange($start, $end); //increment is set to 1 day.

Incremento por mes: -

dateRange($start, $end, "+1 month");//increase by one month

use el tercer parámetro si desea establecer el formato de fecha: -

   dateRange($start, $end, "+1 month", "Y-m-d H:i:s");//increase by one month and format is mysql datetime
usuario2182143
fuente
2

aquí hay una manera:

 $date = new Carbon();
 $dtStart = $date->startOfMonth();
 $dtEnd = $dtStart->copy()->endOfMonth();

 $weekendsInMoth = [];
 while ($dtStart->diffInDays($dtEnd)) {

     if($dtStart->isWeekend()) {
            $weekendsInMoth[] = $dtStart->copy();
     }

     $dtStart->addDay();
 }

¡El resultado de $ weekendsInMoth es una variedad de días de fin de semana!

Jean Souza
fuente
0
$date = new DateTime($_POST['date']);
$endDate = date_add(new DateTime($_POST['date']),date_interval_create_from_date_string("7 days"));

while ($date <= $endDate) {
    print date_format($date,'d-m-Y')." AND END DATE IS : ".date_format($endDate,'d-m-Y')."\n";
    date_add($date,date_interval_create_from_date_string("1 days"));
}

También puede iterar de esta manera, $_POST['date']puede ser abollado desde su aplicación o sitio web. En lugar de $_POST['date']hacerlo, también puede colocar su cadena aquí "21-12-2019". Ambos funcionarán.

zukayu
fuente
0

Si usa Laravel y desea usar Carbon, la solución correcta sería la siguiente:

$start_date = Carbon::createFromFormat('Y-m-d', '2020-01-01');
$end_date = Carbon::createFromFormat('Y-m-d', '2020-01-31');

$period = new CarbonPeriod($start_date, '1 day', $end_date);

foreach ($period as $dt) {
 echo $dt->format("l Y-m-d H:i:s\n");
}

Recuerde agregar:

  • use Carbono \ Carbono;
  • use Carbon \ CarbonPeriod;
Victor nuñez
fuente
0
<?php

    $start_date = '2015-01-01';
    $end_date = '2015-06-30';

    while (strtotime($start_date) <= strtotime($end_date)) {
        echo "$start_daten";
        $start_date = date ("Y-m-d", strtotime("+1 days", strtotime($start_date)));
    }

?>
Soteris 92
fuente