1

I want to fill an array with values. The keys of this array should be readable dates in the format 'YEAR-MONTH-DAY'. Starting point is '2010-5-25'. The process should abort on the current date. Obviously, all dates should be valid dates.

I thought about doing this loop. But it seems that PHP is not able to check the condition of more than one in a 'for' loop. It does not give me any warnings or errors, though.

    for ($d = 25, $m = 5, $y = 2010,
        $this_day = date('j'),
        $this_month = date('n'),
        $this_year = date('Y');
        ($y <= $this_year) && ($m <= $this_month) && ($d <= $this_day);
        $d++)
    {
            $values[$y.'-'.$m.'-'.$d] = 0; //fill array
            $d++;
            if(!checkdate($m, $d, $y)){
                $d = 1;
                $m++;
                if($m > 12) { $m = 1; $y++; }
        }
    }

Doing this with nested loops would be rather painful.

One solution would be to use integer times as keys and then convert them later in another loop into the readable dates.

Is there a more efficient way?

reggie
  • 3,523
  • 14
  • 62
  • 97

6 Answers6

3

Here is code that does some error checking, for example, valid dates provided and start date cannot be bigger than end date:

function arrayKeyDates($start, $end='now') {
    // can use DateTime::createFromFormat() instead
    $startDate = new DateTime($start);
    $endDate = new DateTime($end);

    if ($startDate === false) {
        // invalid start date.
        return;
    }

    if ($endDate === false) {
        // invalid end date.
        return;
    }

    if ($startDate > $endDate) {
        // start date cannot be greater than end date.
        return;
    }

    $dates = array();
    while($startDate <= $endDate) {
        $dates[$startDate->format('Y-n-j')] = 0;
        $startDate->modify('+1 day');
    }

    return $dates;
}

print_r(arrayKeyDate('2014-11-30'));

I get the following output:

Array
(
    [2014-11-30] => 0
    [2014-12-1] => 0
    [2014-12-2] => 0
    [2014-12-3] => 0
    [2014-12-4] => 0
    [2014-12-5] => 0
    [2014-12-6] => 0
    [2014-12-7] => 0
)

Error handling code is left to you.

UPDATE (DateTime::createFromFormat) If you want to create the DateTime objects using a custom format you can, in my function, you can do something like this:

$startDate = DateTime::createFromFormat('Y-n-j', $start);

Where $start would have the value 2010-5-25.

For more information, see: http://php.net/manual/en/datetime.createfromformat.php

ymas
  • 474
  • 6
  • 10
1

Simply you can try using strtotime(). Example:

$values = array();
$oldDate = strtotime('2010-05-25');
while($oldDate <= time()){
    $values[date('Y-m-d', $oldDate)] = 'Your value';
    $oldDate += 86400;
    //Other codes
}
MH2K9
  • 11,951
  • 7
  • 32
  • 49
  • 2
    That should be 86400, not 86000. Also, if you want dates up to but not including today's date, changing `$oldDate <= time()` to `$oldDate < time()` will *NOT* work. – Tom Robinson Dec 07 '14 at 18:10
  • Thanks @TomRobinson, It was a typing mistake :) +1 – MH2K9 Dec 07 '14 at 18:12
1
$startDate = new \DateTime('2010-05-25');
$endDate = new \DateTime();

$interval = new \DateInterval('P1D');
$period = new \DatePeriod ($startDate, $interval, $endDate);

$dates = array();
foreach ($period as $key => $date) {
    $dates[$date->format('Y-m-d')] = null;
}
var_dump($dates);
Mark Baker
  • 209,507
  • 32
  • 346
  • 385
1

I know this is an old question, but might be helpful for new viewers a shorter version

$dummyArray = array_fill(1, 7, 0);
$dates = array_flip(array_map(function($val, $idx) {
    return date_create('2010-5-25')->modify('-' . $idx . ' days')->format('Y-m-d');
}, $dummyArray, array_keys($dummyArray)));

I'm basically generating a dummy array which is going to have the numbers of days I want to extract as index, and then converting those to dates with array_map, after which I just flip the array to have the dates as keys instead of values

Inc33
  • 1,747
  • 1
  • 20
  • 26
  • I think you might as well just use a for-loop to make the code easier to read. This does the same thing: `$dates = []; for ($i = 1; $i <= 7; $i++) { $dates[date_create('2010-5-25')->modify("-$i days")->format('Y-m-d')] = 0; } ` And personally I'd simplify the date creation too: `$dates = []; $dateUnix = strtotime('2010-5-25'); for ($i = 1; $i <= 7; $i++) { $dates[date('Y-m-d', $dateUnix)] = 0; $dateUnix += 24 * 60 * 60; }` – Redzarf Jul 07 '22 at 12:38
0

I took the liberty to clean up your code a little to make it readable:

<?php

$this_day = date('j');
$this_month = date('n');
$this_year = date('Y');
echo sprintf("Today: d-m-y: %s-%s-%s\n", $this_day, $this_month, $this_year);

for ($d = 25,  $m = 5,  $y = 2010;
    ($y <= $this_year) && ($m <= $this_month) && ($d <= $this_day);
    $d++) {
        echo sprintf("Date: d-m-y: %s-%s-%s\n", $d, $m, $y);
        $values[$y.'-'.$m.'-'.$d] = 0; //fill array
        $d++;
        if(!checkdate($m, $d, $y)){
            $d = 1;
            $m++;
            if($m > 12) { $m = 1; $y++; }
     }
}

This shows that the code works perfectly well. That is if you chose the correct condition! Today is the 07th, but your initial values start with the 25th which falsifies the condition. To verify chose a start day of '02' and see the output...

I guess you want to re-check your condition. Most likely it is something else you want to express...

arkascha
  • 41,620
  • 7
  • 58
  • 90
0

First of all; the loop doesn't execute because you are checking separately if year number is lower then current year number, etc. But today is the 7th, and you start at the 25th of may 2010:

$d = 25;
$this_day = date('j'); // today: 7
$loop = $d <= $this_day; // evaluates to false

Because the 'day-check' evaluates to false, the whole expression evaluates to false. So the loop will only start to run on december the 25th.

You can better use the DateTime object to construct the dates and perform modifications on the created object. This will also safe you a lot of sweat with stuff like leap years etc. Example:

for ( 
        $start = new DateTime('2010-05-25'), 
            $today = new DateTime('now') ;
        $start->diff($today)->format('%a') >= 0 ;
        $start->modify('+1 day')
) {
    $values[$start->format('Y-m-d')] = 0;
}

easy does it!

giorgio
  • 10,111
  • 2
  • 28
  • 41