Find recent and upcoming dates - php

I have a two-dimensional array containing events and dates:
$events = array(
array('event' => 'event1', 'date' => '2016-05-05'),
array('event' => 'event2', 'date' => '2016-05-08'),
array('event' => 'event3', 'date' => '2016-05-08'),
array('event' => 'event4', 'date' => '2016-05-10'),
array('event' => 'event5', 'date' => '2016-05-10'),
array('event' => 'event6', 'date' => '2016-05-11'),
array('event' => 'event7', 'date' => '2016-05-11'),
array('event' => 'event8', 'date' => '2016-05-13')
};
Let's say today is 2016-05-10 and I want to create 3 new arrays:
$recent - all events happened on the previous available day
$today - all events today
$upcoming - all events happening on the next available day
$today is easy:
$today = array();
for($i = 0; $i < count($events); ++$i) {
if($events[$i]['date'] == date("Y-m-d") {
array_push($today, $events[$i]['event']);
}
}
So, I will need $recent to contain event2 and event3, and $upcoming to contain event6 and event7.
The question is how to find the recent and the upcoming ones.
*Clarification:
I don't want all the events in $recent happened before today, but the events happened on the previous available day. So in this case only events happened on 2016-05-08

// Take all dates from source array
$dates = array_unique(array_map(function ($i) { return strtotime($i); } , array_column($events, 'date')));
sort($dates);
$today = strtotime('midnight');
// find previouse date. It will be 1970-1-1 if not present in array
$prev = #max(array_filter($dates, function($i) use($today) { return $i < $today; }));
// find ั‚ัƒั‡ะต date. It will be 1970-1-1 if not present in array
$next = #min(array_filter($dates, function($i) use($today) { return $i > $today; }));
$prev = date('Y-m-d', $prev);
$next = date('Y-m-d', $next);
// fill arrays
$recent = array();
$upcoming = array();
$today = array();
for($i = 0; $i < count($events); ++$i) {
if($events[$i]['date'] == date('Y-m-d')) {
array_push($today, $events[$i]['event']);
}
if($events[$i]['date'] == $prev) {
array_push($recent, $events[$i]['event']);
}
if($events[$i]['date'] == $next) {
array_push($upcoming , $events[$i]['event']);
}
}

Try with creating three (3) blank array, check the date is greater or less than today or not and push into array according to conditions.
$today = array();
$upcoming = array();
$recent = array();
$thisDay = date("Y-m-d");
$count = count($events);
$max = max(array_column($events, 'date'));
$min = min(array_column($events, 'date'));
for($i = 0; $i < $count; $i++){
if($events[$i]['date'] > $thisDay){
$max = ($max > $events[$i]['date']) ? $events[$i]['date'] : $max;
array_push($upcoming, $events[$i]['event']);
array_push($upcoming_dates, $events[$i]['date']);
}
elseif($events[$i]['date'] < $thisDay){
$min = ($min < $events[$i]['date']) ? $events[$i]['date'] : $min;
array_push($recent, $events[$i]['event']);
array_push($recent_dates, $events[$i]['date']);
}
else
array_push($today, $events[$i]['event']);
}
foreach($recent_dates as $key => $value){
if($value != $min)
unset($recent[$key]);
}
foreach($upcoming_dates as $key => $value){
if($value != $max)
unset($upcoming[$key]);
}
echo '<pre>';
print_r($today);
print_r($upcoming);
print_r($recent);
Result
Today:
Array
(
[0] => event4
[1] => event5
)
Upcoming:
Array
(
[0] => event6
[1] => event7
)
Recent:
Array
(
[1] => event2
[2] => event3
)
Note: You use push_array which is not any library function in PHP. For Re-index of recent and upcoming you can use array_values.

Another solution should be
$recent = array();
$upcoming = array();
$today = array();
$all_dates = array();
foreach ($events as $event):
array_push($all_dates, $event['date']);
endforeach;
if ($key = array_search('2016-05-10', $all_dates)) {
$prev_date = $all_dates[$key - 1];
}
for ($i = 0; $i < count($all_dates); $i++) {
if ($all_dates[$i] > $all_dates[$key]) {
$next_date = $all_dates[$i + 1];
break;
}
}
for ($i = 0; $i < count($events); ++$i) {
if ($events[$i]['date'] == date('Y-m-d')) {
array_push($today, $events[$i]['event']);
}
if ($events[$i]['date'] == $prev_date) {
array_push($recent, $events[$i]['event']);
}
if ($events[$i]['date'] == $next_date) {
array_push($upcoming, $events[$i]['event']);
}
}
echo '<pre>';
print_r($upcoming);
print_r($today);
print_r($recent);
Output will be
Array
(
[0] => event6
[1] => event7
)
Array
(
[0] => event4
[1] => event5
)
Array
(
[0] => event2
[1] => event3
)

Related

Array to Calendar-Table

I created the following Array ($stuArr) in PHP.
I want to print the Array in an HTML-Table so that I can create a Table like this (Calendar-System):
The numbers in the table are the dates of the month.
And each user has a own row. I generate the table with this:
$days = cal_days_in_month(CAL_GREGORIAN, $month, $year);
$days = $days + 2;
echo "<table border='1'>";
echo "<tr>";
for ($j = 0; $j < $days; $j++) {
echo "<th>$j</th>";
}
echo "</tr>";
//Person
$file = file_get_contents('MOCK_DATA-100.json');
$data = json_decode($file);
//Events
$file2 = file_get_contents('calendar.json');
$data2 = json_decode($file2);
$stuArr = [];
foreach($data as $student) {
$id = $student->id;
$name = $student->name;
$mark = false;
foreach($data2 as $cal) {
if($cal->resource == $id) {
$start = new DateTime(substr($cal->start, 0, 10));
$end = new DateTime(substr($cal->end, 0, 10));
$interval = DateInterval::createFromDateString('1 day');
$period = new DatePeriod($start, $interval, $end);
$dd = [];
if($month == $start->format('n')) {
foreach ($period as $dt) {
if($month != $dt->format('n'))
break;
$dd[] = $dt->format("j");
}
$stuArr[] = [$id, $dd];
}
}
}
}
var_export($stuArr);
foreach($stuArr as $student) {
$id = $student[0];
$dates = $student[1];
}
echo "</table>";
Output of var_export($stuArr);:
array ( 0 => array ( 0 => '2', 1 => array ( 0 => '22', 1 => '23', 2 => '24', 3 => '25', ), ), 1 => array ( 0 => '3', 1 => array ( 0 => '23', 1 => '24', 2 => '25', ), ), )
Thanks for your help! Regards, Fynn
If you have any question for me or need an explanation of some part of the code, just say it!!!
Error:
Try the below code. I can see you printed o-29 as days, try starting from 1 instead of 0 in the loop.
// update inside the Student loop, previous code remains as it is
foreach($stuArr as $student) {
$dates = $student[1];
echo "<tr>";
for ($j = 1; $j <= $days; $j++) {
if(in_array($j, $dates))
echo "<td>X</t>";
else
echo "<td> </td>";
}
echo "</tr>";
}

Calculate Appointments beetween two dates

Situation:
I have arrays with information of the used appointments and the calculated days for the new appointment series based on PHP.
For example, the exist appointment array:
Array
(
[0] => Array
(
[date] => 2019-05-02
[time_start] => 14:00:00
[time_end] => 15:30:00
)
[1] => Array
(
[date] => 2019-05-06
[time_start] => 14:00:00
[time_end] => 15:30:00
)
)
Now, i will check have the calculated series (same array format) collisions with the exist appointments.
My Question:
How can i check if a collision exist beetween the start and end time and if yes how i can give the array a new value with a time windows after or before the exist appointment. This within a time windows from 08:00 am to 4:00 pm.
What i have is the calculation of the appointment days.
private function calculate_dates($data, $measure)
{
$this->load->model('calendar/calendar_model');
$holiday_dates = $this->calendar_model->get_holidays();
foreach ($holiday_dates as $key => $value) {
$holidays[] = $value['holiday_date'];
}
$begin = new DateTime($data->measure_begin);
$end = new DateTime($data->measure_end);
$oneday = new DateInterval("P1D");
$days = json_decode($data->measure_dates);
$wdays = array();
$ue_minutes = 0;
$minutes = ($data->measure_ue * $measure->ue_minutes/2);
$daterange = new DatePeriod( $begin, DateInterval::createFromDateString('+1 weekdays') ,$end );
foreach(new DatePeriod($begin, $oneday, $end->add($oneday)) as $day) {
$day_num = $day->format("N"); /* 'N' number days 1 (mon) to 7 (sun) */
if($day_num < 6 ) { /* weekday */
$wdays[] = $day;
}
}
$count = 1;
foreach($wdays as $date){
foreach ($days as $key => $value) {
if(mb_strtolower($date->format('l')) == $value){
if(($data->measure_ue/2)+1 != $count){
if(in_array($date->format('Y-m-d'), $holidays)) {
$dates[] = $this->close_days($date, $days, true)->format('l, d.m.Y');
} else {
$dates[] = $date->format('l, d.m.Y');
}
$count++;
}
}
}
}
return array(
'dates' => $dates,
'minutes' => round($minutes/count($dates))
);
}
private function close_days($date, $days, $init = false)
{
if($init){
$days[] = 'saturday';
$days[] = 'sunday';
}
if( in_array(mb_strtolower($date->format('l')), $days) ) {
$this->close_days($date->modify('next day'), $days);
}
return $date;
}
Any Ideas for a solution or maybe a code for a better way?

How to assign values from one array to another for n times

I am trying to create a schedule of who uses a specific item on which day.
I have 2 arrays.
one with dates &
another with names and how many days they can use the item.
i have managed to create dates array using this.
function dateArray($from, $to, $value = NULL) {
$begin = new DateTime($from);
$end = new DateTime($to);
$interval = DateInterval::createFromDateString('1 day');
$days = new DatePeriod($begin, $interval, $end);
$baseArray = array();
foreach ($days as $day) {
$dateKey = $day->format("d-m-Y");
$baseArray[$dateKey] = $value;
}
return $baseArray;
}
$dates_array = dateArray('01-01-2014', '30-09-2014',true);
print_r($dates_array );
which gives me dates as
Array
(
[01-01-2014] => 1
[02-01-2014] => 1
[03-01-2014] => 1
[04-01-2014] => 1
[05-01-2014] => 1
[06-01-2014] => 1
[07-01-2014] => 1
[08-01-2014] => 1
[09-01-2014] => 1
and so on.
)
i have another array of names having name as key and days as value , they can use the item like this.
$names_array = array("name1" => "4", "name2" => "3", "name3" => "1");
Now i would like to assign names to dates depending on how many days the person can use the item.
like this.
I need my final output array to be like this
Array
(
[01-01-2014] => name1
[02-01-2014] => name1
[03-01-2014] => name1
[04-01-2014] => name1
[05-01-2014] => name2
[06-01-2014] => name2
[07-01-2014] => name2
[08-01-2014] => name3
[09-01-2014] => name1
and so on. notice name1 comes again
)
so i am trying to get output like above but i am failing at the while loop inside the foreach.
so far i have tried this.
function dateArray($from, $to, $value = NULL) {
$begin = new DateTime($from);
$end = new DateTime($to);
$interval = DateInterval::createFromDateString('1 day');
$days = new DatePeriod($begin, $interval, $end);
$baseArray = array();
foreach ($days as $day) {
$dateKey = $day->format("d-m-Y");
$baseArray[$dateKey] = $value;
}
return $baseArray;
}
$dates_array = dateArray('01-01-2014', '30-09-2014',true);
$names_array = array("name1" => "4", "name2" => "3", "name3" => "1");
print_r($dates_array );
$new_dates = array();
foreach($dates_array as $dates => $key){
//echo $dates;
foreach ($names_array as $name => $days){
while($days <= 1){
$new_dates[$dates] = $name ;
$days = $days - 1;
}
}
}
print_r($new_dates);
But my final array is empty.
so how can i solve this ?
You can use a MultipleIterator whereby the second array (names) loops around when needed:
$names_array = array();
// unwind the array values
foreach (array("name1" => "4", "name2" => "3", "name3" => "1") as $value => $freq) {
for ($i = 0; $i < $freq; ++$i) {
$names_array[] = $value;
}
}
// attach both arrays
$m = new MultipleIterator;
$m->attachIterator(new ArrayIterator(array_keys($dates_array)));
$m->attachIterator(new InfiniteIterator(new ArrayIterator($names_array)));
// build final array
$result = array();
foreach ($m as $value) {
$result[$value[0]] = $value[1];
}
It should probably go like this...
while($days <= 1){
$new_dates[$dates] = $name ;
$names_array[$name] = $days - 1;
}
Hi You can try this one
$dates_array = array_keys(dateArray('01-01-2014', '30-09-2014',true));
$names_array = array("name1" => "4", "name2" => "3", "name3" => "1");
$new_dates = array();
$daysindex = 0;
while($daysindex < count($dates_array)){
foreach ($names_array as $name => $day){
for($x = 0; $x<$day; $x++){
if(isset($dates_array[$daysindex])){
$new_dates[$dates_array[$daysindex]] = $name ;
$daysindex++;
}
}
}
}
print_r($new_dates);
$dates = dateArray('01-01-2014', '30-09-2014',true);
$names = array('name1' => 4,'name2' => 3,'name3' => 1);
$count = current($names);
$name = key($names);
foreach($dates as &$value) {
$value = $name;
//if we've displayed a name $count times, move to the next name
if(--$count == 0) {
//if we're at the end of $names, wrap around
if(false === next($names)) {
reset($names);
}
$count = current($names);
$name = key($names);
}
}
print_r($dates);

Split an array in sub arrays of consecutive dates

For a rent application, I have an array $dates like this:
Array
(
[2013-07-19] => 1
[2013-07-21] => 3
[2013-07-23] => 2
[2013-07-24] => 4
[2013-07-25] => 4
[2013-07-26] => 2
[2013-07-27] => 2
[2013-07-30] => 3
[2013-07-31] => 1
)
The date is the key, and the values are the number of items rent in that day for a specific product
How can I split this array in many sub arrays containing each a list of consecutive days?
Like this:
Array
(
[0] => Array
(
[2013-07-19] => 1
)
[1] => Array
(
[2013-07-21] => 3
)
[2] => Array
(
[2013-07-23] => 2
[2013-07-24] => 4
[2013-07-25] => 4
[2013-07-26] => 2
[2013-07-27] => 2
)
[3] => Array
(
[2013-07-30] => 3
[2013-07-31] => 1
)
)
$newArray = array();
foreach ($array as $date => $value)
{
// Make sure the newArray starts off with at least one element
if (empty($newArray))
$newArray[] = array();
// Calculate the difference in dates.
// (I like using DateTime, but use whichever method you like)
$dateTime = new DateTime($date);
$lastDateTime = new DateTime($lastDate);
$dateDiff = $dateTime->diff($lastDateTime);
// Add a new array to the end if the difference between this element and the last was more than a day
if ($dateDiff->days > 1)
$newArray[] = array();
// We can now be guaranteed that the last element of $newArray is the one we want to append to
$newArray[count($newArray) - 1][$date] = $value;
// Keep track of the last date you saw
$lastDate = $date;
}
Here it is in action: https://eval.in/38039
$newArray = array();
$i = 0;
foreach ($array as $date => $key) {
$thisDay = end(explode('-', $date));
$nextDay = end(explode('-', next($array[$date])));
if ($thisDay + 1 != $nextDay + 0)
$i++;
if (!isset($newArray[$i])) {
$newArray[$i] = array($date => $key);
} else {
if (!isset($newArray[$i][$date])) {
$newArray[$i][$date] = $key;
} else {
$newArray[$i][$date] = $key;
}//END IF
}//END IF
}//END FOREACH LOOP
This is the code i would use to do what you are asking.
UPDATE:
I was wrong above. i have altered the code to work this time:
$newArray = array();
$i = 0;
foreach ($array as $date => $key) {
$thisDay = end(explode('-', $date));
$nextDay = array_key_exists(date('Y-m-d', strtotime($date . ' +1 day')), $array);
if (!isset($newArray[$i])) {
$newArray[$i] = array($date => $key);
} else {
if (!isset($newArray[$i][$date])) {
$newArray[$i][$date] = $key;
} else {
$newArray[$i][$date] = $key;
}//END IF
}//END IF
if (!$nextDay)
$i++;
}//END FOREACH LOOP
Here is my test case:
<?php
$array = array(
'2013-07-19' => 1,
'2013-07-21' => 3,
'2013-07-23' => 2,
'2013-07-24' => 4,
'2013-07-25' => 4,
'2013-07-26' => 2,
'2013-07-27' => 2,
'2013-07-30' => 3,
'2013-07-31' => 1
);
echo '<pre>' . print_r($array, true) . '</pre>';
$newArray = array();
$i = 0;
foreach ($array as $date => $key) {
$thisDay = end(explode('-', $date));
$nextDay = array_key_exists(date('Y-m-d', strtotime($date . ' +1 day')), $array);
if (!isset($newArray[$i])) {
$newArray[$i] = array($date => $key);
} else {
if (!isset($newArray[$i][$date])) {
$newArray[$i][$date] = $key;
} else {
$newArray[$i][$date] = $key;
}//END IF
}//END IF
if (!$nextDay)
$i++;
}//END FOREACH LOOP
echo '<pre>' . print_r($newArray, true) . '</pre>';
?>
you can do it like this:
$data = array(
'2013-07-19' => 1,
'2013-07-21' => 3,
'2013-07-23' => 2,
'2013-07-24' => 4,
'2013-07-25' => 4,
'2013-07-26' => 2,
'2013-07-27' => 2,
'2013-07-30' => 3,
'2013-07-31' => 1
);
$result = array();
$ref = new DateTime('1821-11-11');
foreach ($data as $datum => $nb) {
if ($ref->add(new DateInterval('P1D'))->format('Y-m-d')!=$datum) {
$result[] = array();
$ref = new DateTime($datum);
}
$result[array_pop(array_keys($result))][$datum] = $nb;
}
print_r($result);

Most efficient way to get array of months in array of years

What is the most efficient way to get an array of months, from a specified date, up until the present day, grouped by year.
Eg getMonths("August 2012") would output
array(
array("Year"=>"2013", "months" = array(
"February", "January")
),
array("Year"=>"2012", "months" = array(
"December", "November","October", "September", "August")
)
)
So far I've got:
$start = strtotime('2012-08-01');
$end = time();
$month = $start;
$months[] = date('F', $start);
while($month <= $end) {
$month = strtotime("+1 month", $month);
$months[] = date('F', $month);
}
This is outputting the correct months, but not grouping them into years.
Thanks
You can try
function getMonths($month,$count = 1) {
$now = new DateTime();
$start = DateTime::createFromFormat("F Y", $month);
$list = array();
$interval = new DateInterval(sprintf("P%dM",$count));
while ( $start <= $now ) {
$list[$start->format("Y")][] = $start->format("F");
$start->add($interval);
}
return $list;
}
print_r(getMonths("August 2012"));
Output
Array
(
[2012] => Array
(
[0] => August
[1] => September
[2] => October
[3] => November
[4] => December
)
[2013] => Array
(
[0] => January
[1] => February
)
)
Since the answer posted here did not work for me (also tried online sandbox to be sure) i wrote a method that works with the very most versions of PHP:
function getMonths($monat, $year) {
$list = array();
for(;$monat <= 12;$monat++) {
if($year == date("Y") && $monat == date("m")) { // exit on current month+year
break;
}
if(!isset($list[ $year ])) {
$list[ $year ] = array();
}
$list[ $year ][ str_pad($monat, 2, '0', STR_PAD_LEFT) ] = date("F", strtotime('01.' . $monat . '.' . $year));
if($monat == 12) {
$monat = 0;
$year++;
}
}
return $list;
}

Categories