Manipulating arrays of dates in PHP - php

I'm having a lot of difficulty approaching a piece of code in PHP. I have an array of dates and values, for example
dates = (2014-12-01,2014-12-02,2014-12-08,2014-12-09,2014-12-10,2014-12-11)
values = (5,3,7,8,9,2)
You'll note that 12/01 is a Monday, as is 12/08. I'd like to form 4 arrays from these two arrays:
monday = (5,7)
tuesday = (3,8)
wednesday = (0,9)
thursday = (0,2)
You'll note that the arrays are formed by grabbing the values associated with the days of the week. However, in the case that a Wednesday date exists, for example, but the prior Tuesday does not, then the array should have a "0". In other words, the 4 arrays should all be the same length.
Can anyone help me write code in PHP to achieve this? Thanks in advance!
NOTE: So far, I have only determined how to find the day of the week from a date: date('l', strtotime("2014-12-08")); I really can't figure out the general algorithm to solve this.

$dates = array( '2014-12-01','2014-12-02','2014-12-08','2014-12-09',
'2014-12-10','2014-12-11' );
$values = array( 5, 3, 7, 8, 9, 2 );
$date = strtotime(min($dates));
$stop = strtotime(max($dates));
$dates = array_flip($dates);
$out = array();
while($date <= $stop)
{
$tmp = date('Y-m-d', $date);
$out[date('l', $date)][] = isset($dates[$tmp]) && isset($values[$dates[$tmp]]) ?
$values[$dates[$tmp]] : 0;
$date = strtotime('+1 day', $date);
}
print_r($out);
Result:
Array
(
[Monday] => Array
(
[0] => 5
[1] => 7
)
[Tuesday] => Array
(
[0] => 3
[1] => 8
)
[Wednesday] => Array
(
[0] => 0
[1] => 9
)
[Thursday] => Array
(
[0] => 0
[1] => 2
)
[Friday] => Array
(
[0] => 0
)
[Saturday] => Array
(
[0] => 0
)
[Sunday] => Array
(
[0] => 0
)
)
ps: how can I get the an array of all the dates included in the "dates" array associated with only all the Mondays?
Modify the code as, for example:
$tmp = date('Y-m-d', $date);
$exists = isset($dates[$tmp]) && isset($values[$dates[$tmp]]);
$out[date('l', $date)]['numbers'][] = $exists ? $values[$dates[$tmp]] : 0;
if ($exists) $out[date('l', $date)]['dates'][] = $tmp;
$date = strtotime('+1 day', $date);
You'll get an output as (example for monday)
[Monday] => Array
(
[numbers] => Array
(
[0] => 5
[1] => 7
)
[dates] => Array
(
[0] => 2014-12-01
[1] => 2014-12-08
)
)

Might be a better way to get the 0s in there without another loop but I'm headed out:
foreach($dates as $key => $val) {
$day = date('l', strtotime($val));
$result[$day][] = $values[$key];
}
foreach($result as &$val) {
if(count($val) == 1) {
array_unshift($val, 0);
}
}
print_r($result);

Related

Filter multidimensional array and push in new one

I am trying to build a class schedule that takes a .csv with data for the whole semester. I have this multidimensional array, which contains the date, class, instructor, room, and notes for every day of the semester:
Array (
Array (
[0] => 1
[1] => 2019-04-02
[2] => Study Skills
[3] => 371
[4] => Mr Teacher
[5] => 0
[6] =>
)
Array ( ... )
...)
I managed to display the schedule for the whole semester in one table. However, ideally, I would filter out the data for each month and then push in into a new multidimensional array for the whole semester.
I was able to filter out individual months by comparing it a to hardcoded string but I obviously don't want to do that for the whole semester:
$may = "05";
$classMay = [];
foreach ($days as $day){
if (strrpos($day[1], $may, -5)){
array_push($classMay, $day);
}
};
Is there a more efficient solution to this?
Any insight is much appreciated!
Just get the month name from the date of each one and append the day data onto an array indexed by the month:
foreach($days as $day) {
$month = date('F', strtotime($day[1]));
$result[$month][] = $day;
}
Now you should have an array that looks similar to this:
Array
(
[January] => Array
(
[0] => Array
(
[0] => 1
[1] => 2019-01-01
//etc
)
[1] => Array
(
[0] => 3
[1] => 2019-01-02
//etc
)
)
[February] => Array
(
[0] => Array
(
[0] => 10
[1] => 2019-02-01
//etc
)
[1] => Array
(
[0] => 30
[1] => 2019-02-02
//etc
)
)
)
For fun you could loop 12 months and filter on the month:
foreach(range(1, 12) as $m) {
$month = date('F', strtotime($m));
$result[$month] = array_filter($days, function($v) use($month) {
return $month == date('F', strtotime($v[1]));
});
}

Weird PHP date incrementation

I was trying to do a loop to find the weekends between two dates and something was really damn strange.
I have to following code which in my opinion should be working fine.
$weekends = array();
// yyyy-mm-dd
$firstWeekend = '2015-09-04';
$lastWeekend = '2015-12-25';
$firstWeekendTime = strtotime($firstWeekend);
$lastWeekendTime = strtotime($lastWeekend);
$totalWeekends = 0;
for ($i = $firstWeekendTime; $i <= $lastWeekendTime; $i += (7 * 86400)) {
$totalWeekends++;
$weekends[date('Y-m-d', $i)] = array(
date('Y-m-d', $i),
date('Y-m-d', strtotime(date('Y-m-d', $i) . '+ 2 days'))
);
}
Eg. output:
[2015-10-16] => Array
(
[0] => 2015-10-16
[1] => 2015-10-18
)
[2015-10-23] => Array
(
[0] => 2015-10-23
[1] => 2015-10-25
)
[2015-10-29] => Array
(
[0] => 2015-10-29
[1] => 2015-10-31
)
[2015-11-05] => Array
(
[0] => 2015-11-05
[1] => 2015-11-07
)
But this is not correct cause the next weekend after 2015-10-23 is 2015-10-30.
So the output should be this:
[2015-10-16] => Array
(
[0] => 2015-10-16
[1] => 2015-10-18
)
[2015-10-23] => Array
(
[0] => 2015-10-23
[1] => 2015-10-25
)
[2015-10-30] => Array
(
[0] => 2015-10-30
[1] => 2015-11-01
)
[2015-11-05] => Array
(
[0] => 2015-11-05
[1] => 2015-11-07
)
I finally made it work by putting a default timezone and without chaning anything else, it worked.
date_default_timezone_set('America/Los_Angeles');
Can someone understand why does this incrementation fail without the timezone?
And the weirdest thing is that it only fails around ~2015-10-25
I don't want other options to find the weekend... i just want to understand why it acts like this.
Thank you.
Just you have to change the for loop condition with increment value like this
for ($i = $firstWeekendTime; $i <= $lastWeekendTime; $i = strtotime(date('Y-m-d', strtotime(date('Y-m-d', $i) . '+ 7 days'))))
instead of
for ($i = $firstWeekendTime; $i <= $lastWeekendTime; $i += (7 * 86400))

Selecting a certain item from multi-dimensional array

I have an multi-dimensional array called shifts which contains the day (e.g. Monday) and then the shift (e.g. 12:00 - 16:00)
I'm looking to do something like:
$monday = shift from array where day equals Monday
My array currently looks like:
Array ( [0] => Array ( [day] => Saturday [shift] => Day Off! )
[1] => Array ( [day] => Sunday [shift] => Day Off! )
[2] => Array ( [day] => Monday [shift] => 11:00-19:00 )
[3] => Array ( [day] => Tuesday [shift] => 08:00-17:00 )
[4] => Array ( [day] => Wednesday [shift] => 08:00-17:00 )
[5] => Array ( [day] => Thursday [shift] => 16:00-01:00 )
[6] => Array ( [day] => Friday [shift] => 16:00-01:00 ) )
Array is built using this code:
$shifts = array();
$sql = mysql_query("SELECT day, shift FROM ps_shifts WHERE user_id = '$user_id' AND week_begin = '$week_1_begin'");
while($row = mysql_fetch_assoc($sql)) {
$shifts[] = $day;
}
/* to refine on what was said above lets take the the data as such:*/
$data = array(
array ( 'day' => 'Saturday', 'shift' => 'Day Off!' ),
array ( 'day' => 'Sunday', 'shift' => 'Day Off!' ),
array ( 'day' => 'Monday', 'shift' => '11:00-19:00' ),
/* ... */
);
/* we then take that data and transform it, that is flatten it to day=>shift. call it shifts*/
$shifts = array();
$days = array('Saturday','Sunday','Monday','Tuesday','Wednesday','Thursday', 'Friday');
foreach ($data as $i=>$s) {
$shifts[$days[$i]] = $data[$i]['shift'];
}
/* this returns an array like:
$shifts = array (
'Saturday' => 'Day Off!',
'Sunday' => 'Day Off!',
'Monday' => '11:00-19:00',
);
*/
/* then to get the shift for any day is as simple as.*/
$monday_shift = $shifts['Monday'];
print "monday shift is: $monday_shift\n";
You could use the day as the array key.
So:
while($row = mysql_fetch_assoc($sql)) {
$shifts[$day['day']] = $day;
}
Then you could get it by doing this:
$shift_time = $shifts['Monday']['shift'];
Solved based on 'jd182' anwser, however the provided code didn't work so I modified to this:
$shifts = array();
$sql = mysql_query("SELECT day, shift FROM ps_shifts WHERE user_id = '$user_id' AND week_begin = '$week_1_begin'");
while($row = mysql_fetch_assoc($sql)) {
$shifts[$row['day']] = $row['shift'];
}
echo $shifts['Monday'];

Fill in missing elements of an array of date objects in PHP [duplicate]

This question already has answers here:
Push rows with default values into an array containing dates so there are no gaps between dates
(4 answers)
Closed 5 months ago.
I have an array of objects in php which looks like:
Array
(
[0] => Array
(
[day] => 1/23/2013
[executions] => 1
)
[1] => Array
(
[day] => 1/24/2013
[executions] => 1
)
[2] => Array
(
[day] => 1/27/2013
[executions] => 10
)
[3] => Array
(
[day] => 1/29/2013
[executions] => 1
)
[4] => Array
(
[day] => 1/30/2013
[executions] => 3
)
[5] => Array
(
[day] => 2/8/2013
[executions] => 1
)
[6] => Array
(
[day] => 2/11/2013
[executions] => 3
)
)
I am building a graph of this data, and basically it represents the last 30 days. The problem is I don't get the missing days, i.e. when there was no executions from the query. I am looking to fill in these missing days with PHP, simple set the day to the correct date, and executions to 0. Thus the result array should contain 30 elements, assuming start is 1/18/2013 and end is today 2/17/2013.
Any idea of the best algorithm to accomplish this in PHP?
Something like:
$start = '1/18/2013';
$end = '2/17/2013';
$range = new DatePeriod(
DateTime::createFromFormat('m/d/Y', $start),
new DateInterval('P1D'),
DateTime::createFromFormat('m/d/Y', $end));
$filler = array();
foreach($range as $date)
$filler[] = array(
'day' => $date->format('m/d/Y'),
'execution' => 0,
};
$array += $filler;
Loop through each date using DateTime:
$start = new DateTime('2013-01-18');
$end = new DateTime('2013-02-17');
while ($start <= $end)
{
$current_date = $start->format('m/d/Y');
// Right here look in your array and see if that date exists
// and do whatever you need to do if it does/does not
$start->modify("+1 day");
}
You may use this:
$startDate = new DateTime ( "-30 days" );
$dateItter = new DatePeriod (
$startDate,
new DateInterval ('P1D'),
30
);
$original = array (
array (
'days' => '02/16/2013',
'executions' => 5
)
);
$result = array ();
foreach ( $dateItter as $date )
{
$executions = 0;
foreach ( $original as $item ) {
if ( $item['days'] == $date->format ( 'm/d/Y' ) )
$executions = $item['executions'];
}
$result[] = array (
"day" => $date->format ( 'm/d/Y' ),
"executions" => $executions
);
}
var_dump ( $result );
It is slow for large amount of data but for 30 items will be ok!

Comparing multiple different dates and getting the average in PHP

I use a function called count_days($date1,$date2) that counts the number of days between two dates. But, my question is: the dates come from the DB, in an array like:
Array (
[imac] => Array (
[0] => 2002-10-10
[1] => 2003-11-22
[3] => 2004-11-10
)
[iphone] => Array (
[0] => 2007-09-11
[1] => 2008-05-12
[2] => 2009-06-14
[3] => 2010-06-05
)
)
As you can see the products may have a different number of subarrays. I want to count the days between the first and the next date (and so on!) and then get the average of days.
The DateInterval class is great for this kind of date arithmetic. You can use DateTime::add, DateTime::subtract and DateTime::diff to work with them.
<?php
$types = array(
'imac' => array ('2002-10-10', '2003-11-22', '2004-11-10'),
'iphone' => array ( '2007-09-11', '2008-05-12', '2009-06-14', '2010-06-05'),
);
$typeIntervals = array();
$typeAverage = array();
foreach ($types as $type=>$dates) {
$last = null;
$typeIntervals[$type] = array();
foreach ($dates as $date) {
$current = new DateTime($date);
if ($last) {
$interval = $current->diff($last);
$typeIntervals[$type][] = $interval->days;
}
$last = $current;
}
$typeAverage[$type] = array_sum($typeIntervals[$type]) / count($typeIntervals[$type]);
}
print_r(typeIntervals);
print_r($typeAverage);
This will output:
Array (
[imac] => Array (
[0] => 408
[1] => 354
)
[iphone] => Array (
[0] => 244
[1] => 398
[2] => 356
)
)
Array (
[imac] => 381
[iphone] => 332.66666666667
)
try smth like this ( not tested )
$lastDate = $dbArray[0][0];
$daysArray = array();
foreach ( $dbArray as $value )
{
if ( is_array($value) )
{
foreach ( $value as $v )
{
$daysArray[] = count_days($lastDate, $v);
$lastDate = $v;
}
} else {
//not an array check if it's a date and test it here
}
}
$average = array_sum($daysArray)/count($daysArray);

Categories