How to get only holiday date from date array - php

I'm trying to make a holiday array, it is based on work_day.
For example is if in 1 group there's only day 1-2 (sunday-monday), then the other day (tuesday-saturday) is holiday. And based on that days, I want to get a holiday date array from start of the year until now.
I have a table like this:
attendance_group_id | day
GROUP-001 | 1
GROUP-001 | 2
GROUP-002 | 1
GROUP-003 | 1
What I've done first is getting all data from work_day table using code bellow:
foreach ($group_work_hour as $hours) {
foreach ($hours as $hour){
$work_day = (object) array();
$work_day->group_id = $hour->attendance_group_id;
$work_day->day = $hour->day;
$work_day_arr[] = $work_day;
}
}
And the result from code above is like bellow, every group can have day up to 7 day (1-7). 1 for sunday and 7 for saturday.
Array work day
array (
0 =>
(object) array(
'group_id' => '854b5b57-f863-4e48-ba9b-617899c64750',
'day' => 2,
),
1 =>
(object) array(
'group_id' => '854b5b57-f863-4e48-ba9b-617899c64750',
'day' => 3,
),
2 =>
(object) array(
'group_id' => '854b5b57-f863-4e48-ba9b-617899c64750',
'day' => 4,
),
3 =>
(object) array(
'group_id' => '854b5b57-f863-4e48-ba9b-617899c64750',
'day' => 5,
),
4 =>
(object) array(
'group_id' => '854b5b57-f863-4e48-ba9b-617899c64750',
'day' => 6,
),
5 =>
(object) array(
'group_id' => '854b5b57-f863-4e48-ba9b-617899c64750',
'day' => 7,
),
6 =>
(object) array(
'group_id' => 'f3f739d2-77fe-4e1f-b7fc-44242f52610b',
'day' => 2,
),
7 =>
(object) array(
'group_id' => 'f3f739d2-77fe-4e1f-b7fc-44242f52610b',
'day' => 3,
),
8 =>
(object) array(
'group_id' => 'f3f739d2-77fe-4e1f-b7fc-44242f52610b',
'day' => 4,
),
9 =>
(object) array(
'group_id' => 'f3f739d2-77fe-4e1f-b7fc-44242f52610b',
'day' => 5,
),
10 =>
(object) array(
'group_id' => 'f3f739d2-77fe-4e1f-b7fc-44242f52610b',
'day' => 6,
),
And what I've done next is to get every date from start of the year until today and store it to an array.
$now = \Carbon\Carbon::now()->format('Y-m-d');
$start = \Carbon\Carbon::parse($now)->startOfYear()->format('Y-m-d');
$dateRangePeriod = \Carbon\CarbonPeriod::create($start, $now);
$dateRange = [];
foreach ($dateRangePeriod as $key => $date) {
$dateRange[] = $date->format('Y-m-d');
}
The result from code above is like this:
Array date
array (
0 => '2022-04-01',
1 => '2022-04-02',
2 => '2022-04-03',
3 => '2022-04-04',
4 => '2022-04-05',
5 => '2022-04-06',
6 => '2022-04-07',
7 => '2022-04-08',
8 => '2022-04-09',
9 => '2022-04-10',
10 => '2022-04-11',
11 => '2022-04-12',
12 => '2022-04-13',
)
What I want to do next is, I want to get only holiday date from array date above. But I don't know how to do that because from work_day I only get group_id and the number of day.
How to know if the day from array date is the holiday based on array work_day.
I'm trying some way to doing it, but I can't found the solution yet. I've tried like code bellow, but still not working:
// Loop all date from array date
foreach ($dateRange as $range) {
// Get number of day from date
$day = date('N', strtotime($range));
// Loop work day array
foreach ($work_day_arr as $work) {
// When day from work not equals to day from date (this is a right way to check if days from array date is a holiday)?
if($work->day != $day) {
// Check if group_id & off_date (holiday date) is not set
if(!isset($data['attendance_group_id'], $data['off_date'])) {
$data['attendance_group_id'] = $work->group_id;
$data['off_date'] = date('Y-m-d', strtotime($range));
$objData[] = $data;
}
}
}
}
The example result that I want is something like this (excluding holiday date):
From:
array (
0 => '2022-04-01', // holiday date
1 => '2022-04-02',
2 => '2022-04-03',
3 => '2022-04-04',
4 => '2022-04-05',
5 => '2022-04-06', // holiday date
6 => '2022-04-07',
7 => '2022-04-08',
8 => '2022-04-09',
9 => '2022-04-10',
10 => '2022-04-11',
11 => '2022-04-12', // holiday date
12 => '2022-04-13', // holiday date
)
To (excluding holiday date):
array (
0 => '2022-04-02',
1 => '2022-04-03',
2 => '2022-04-04',
3 => '2022-04-05',
4 => '2022-04-07',
5 => '2022-04-08',
6 => '2022-04-09',
7 => '2022-04-10',
8 => '2022-04-11',
)
Another case example
From array work day:
day = 1, which is Sunday
array date:
01-01-2022
02-02-2022 // if this date == sunday, then this is a holiday
03-02-2022
result:
02-02-2022 // only get holiday date

Related

PHP - Get latest entry for each element ID in assoc array [duplicate]

This question already has answers here:
Group rows of data by one column and find max value in another column within each group
(4 answers)
Closed 7 months ago.
I have some json data which I've decoded into an assoc array. This array contains a set of names, their respective ids, some relevant data and year. Here is a sample of my data:
Name
ID
Year
Gary
1
2016
Miller
2
2018
Spike
3
2019
Miller
2
2020
Gary
1
2018
Miller
2
2019
Gary
1
2017
Spike
3
2020
I have sorted this in descending order of year, but I would also like to retrieve all 3 IDs by their latest entry only. Below is my expected output:
Name
ID
Year
Miller
2
2020
Spike
3
2020
Gary
1
2018
I am not clear on how to get the latest entry from each respective ID.
One of the easier ways to do this is to loop through the sorted array and extract the record with the first instance of each ID into another array, keyed by the ID so we know when we have already found that ID.
<?php
$data = [
['Name' => 'Gary', 'ID' => 1, 'Year' => 2016],
['Name' => 'Miller', 'ID' => 2, 'Year' => 2018],
['Name' => 'Spike', 'ID' => 3, 'Year' => 2019],
['Name' => 'Miller', 'ID' => 2, 'Year' => 2020],
['Name' => 'Gary', 'ID' => 1, 'Year' => 2018],
['Name' => 'Miller', 'ID' => 2, 'Year' => 2019],
['Name' => 'Gary', 'ID' => 1, 'Year' => 2017],
['Name' => 'Spike ', 'ID' => 3, 'Year' => 2020]
];
// Sort all records by year in descending order
usort($data, function ($a, $b)
{
return $b['Year'] <=> $a['Year'];
});
// Create a temporary array for our unique entries. We will use the IDs as the keys
$latestEntryBuffer = [];
// Loop through the sorted data
foreach ($data as $currRow)
{
/*
Set a var for the ID, less typing, less chance for error,
our IDE will let us know if we mistype it somewhere
*/
$currID = $currRow['ID'];
/*
If this ID does not have a record in the buffer yet, set
the current record in the buffer. Since we sorted all data
by year descending, the first instance of the ID we encounter
will be the most recent
*/
if (!array_key_exists($currID, $latestEntryBuffer))
{
$latestEntryBuffer[$currID] = $currRow;
}
}
// Put all of the rows from the buffer into a simple array
$lastestEntries = array_values($latestEntryBuffer);
print_r($lastestEntries);
echo PHP_EOL;
Output:
Array
(
[0] => Array
(
[Name] => Miller
[ID] => 2
[Year] => 2020
)
[1] => Array
(
[Name] => Spike
[ID] => 3
[Year] => 2020
)
[2] => Array
(
[Name] => Gary
[ID] => 1
[Year] => 2018
)
)
Alternatively you could sort by year ascending and blindly assign each record to the buffer by ID, the last record for each ID would be the most recent.

How to count array with the same month

$dates = array('2017-03-24 01:48:09', '2017-03-24 11:48:09', '2017-04-07 01:12:19', '2017-04-14 01:49:09', '2017-04-21 01:45:09', '2017-04-28 01:38:09');
if given array above..
i'm making a report to monitor user growth monthly.. i want to count the no. of entries per month
sample April 2 counts
$dates = array('2017-03-24 01:48:09', '2017-03-24 11:48:09', '2017-04-07 01:12:19', '2017-04-14 01:49:09', '2017-04-21 01:45:09', '2017-04-28 01:38:09');
$count = array();
foreach ($dates as $d) {
$count[date('m', strtotime($d))]++;
}
print_r($count);
Output will be:
Array ([03] => 2 [04] => 4 )
That is: 03 (March) has 2 values in given array.
If you need 03 as March, then use:
$count[date('F', strtotime($d))]++;
Then, output will be:
Array ([March] => 2 [April] => 4 )
<?php
$dates = array('2017-03-24 01:48:09', '2017-03-24 11:48:09', '2017-04-07 01:12:19', '2017-04-14 01:49:09', '2017-04-21 01:45:09', '2017-04-28 01:38:09');
foreach($dates as $date)
$year_months[] = date('Y-m', strtotime($date));
var_export($year_months);
var_export(array_count_values($year_months));
Output:
array (
0 => '2017-03',
1 => '2017-03',
2 => '2017-04',
3 => '2017-04',
4 => '2017-04',
5 => '2017-04',
)array (
'2017-03' => 2,
'2017-04' => 4,
)

Get data from mysql and group them in weeks and also display the dates

I am printing data on weekly basis. I need to add one thing to my query. I want the starting and ending date of the week as well along with data.
At the moment the data is like this
[0] => Array
(
[WEEK] => 7
[total_sub_total] => 110.30
[total_tax] => 9.92
[total_restaurant_delivery_fee] => 0
)
[0] => Array
(
[WEEK] => 8
[total_sub_total] => 6540.00
[total_tax] => 1046.40
[total_restaurant_delivery_fee] => 0
)
I want the dates as well of that week. for example, it should be
[0] => Array
(
[WEEK] => 8,
[starting_week_date] => 2018-02-21 13:18:10,
[ending_week_date] => 2018-02-26 13:18:10,
[total_sub_total] => 6540.00
[total_tax] => 1046.40
[total_restaurant_delivery_fee] => 0
)
Here is the code
public function getWeeklyEarnings($restaurant_id)
{
return $this->find('all', array(
//'contain' => array('OrderMenuItem', 'Restaurant', 'OrderMenuItem.OrderMenuExtraItem', 'PaymentMethod', 'Address','UserInfo','RiderOrder.Rider'),
'conditions' => array(
'Order.restaurant_id' => $restaurant_id,
'Order.status' => 2,
'Order.created > DATE_SUB(NOW(), INTERVAL 4 WEEK)'
),
'fields' => array(
'WEEK(Order.created) AS WEEK',
'sum(Order.sub_total) AS total_sub_total',
'sum(Order.tax) AS total_tax',
'sum(Order.restaurant_delivery_fee) AS total_restaurant_delivery_fee',
),
'group' => array('WEEK(Order.created)'),
'recursive' => 0
));
}
There is no simple function that will yield a week interval (or start/end date of a week) given a week number. You have to find these dates manually.
try this :
'fields' => array(
'WEEK(Order.created) AS WEEK',
'DATE_ADD(Order.created, INTERVAL(1-DAYOFWEEK(Order.created)) DAY) AS week_start',
'DATE_ADD(Order.created, INTERVAL(7-DAYOFWEEK(Order.created)) DAY) AS week_end',
'sum(Order.sub_total) AS total_sub_total',
'sum(Order.tax) AS total_tax',
'sum(Order.restaurant_delivery_fee) AS total_restaurant_delivery_fee'
)
The DAYOFWEEK() function returns an integer ranging from 1 (Sunday) to 7 (Saturday). So if Order.created happens to be Tuesday we get the following statements:
DATE_ADD(Order.created, INTERVAL -2 DAY)
which essentially means “subtract 2 days from Order.created (which is that week’s Sunday) and also:
DATE_ADD(Order.created, INTERVAL 4 DAY)
which yields the date of that week’s Friday.
Or, you can try :
'fields' => array(
'WEEK(Order.created) AS WEEK',
'MIN(Order.created) as week_start',
'MAX(Order.created) as week_end',
'sum(Order.sub_total) AS total_sub_total',
'sum(Order.tax) AS total_tax',
'sum(Order.restaurant_delivery_fee) AS total_restaurant_delivery_fee'
)
But you have to be sure that you have orders on every single day of the week.
I hope this helps.

how would I detect a non-overlap of two time periods?

I have a user input form where user select the date in (YYYY-mm-dd) format, and start time in (H:i) and end time in (H:i) format, or assume i have three variable with following values.
$date = '2012-11-22';
$startTime = '1:00';
$endTime = '4:00';
i now have to compare this values with existing array of values. my existing array look like this.
Array
(
[0] => Array
(
[id] => 1
[start_datetime] => 2012-11-22 02:30:00
[end_datetime] => 2012-11-22 05:00:00
)
[1] => Array
(
[id] => 2
[start_datetime] => 2012-11-22 00:00:00
[end_datetime] => 2012-11-22 02:30:00
)
[2] => Array
(
[id] => 3
[start_datetime] => 2012-11-22 05:00:00
[end_datetime] => 2012-11-22 08:00:00
)
[3] => Array
(
[id] => 4
[start_datetime] => 2012-11-22 08:00:00
[end_datetime] => 2012-11-22 11:00:00
)
[4] => Array
(
[id] => 5
[start_datetime] => 2012-11-22 11:00:00
[end_datetime] => 2012-11-22 17:00:00
)
)
i have to check if the user input selected [date, startTime, and endTime] has any of the slots already booked in the given array of time slots. from what i see the solution is to first split and match the date, if it matches the date then time needs to be matched accordingly. i am confused about how to go with it. i hope to get some simple solution from you guys :)
thank you.
UPDATE:
i tried doing this way.
$arenaSurfaceBooking = array(
array(
'id' => 1,
'start_datetime' => '2012-11-22 02:30:00',
'end_datetime' => '2012-11-22 05:00:00',
),
array(
'id' => 2,
'start_datetime' => '2012-11-22 00:00:00',
'end_datetime' => '2012-11-22 02:30:00',
),
array(
'id' => 3,
'start_datetime' => '2012-11-22 05:00:00',
'end_datetime' => '2012-11-22 08:00:00',
),
array(
'id' => 4,
'start_datetime' => '2012-11-22 08:00:00',
'end_datetime' => '2012-11-22 11:00:00',
),
array(
'id' => 5,
'start_datetime' => '2012-11-22 11:00:00',
'end_datetime' => '2012-11-22 17:00:00',
)
);
foreach($arenaSurfaceBooking as $booking) {
$bookedDateTimestamp = strtotime(date('Y-m-d', strtotime($booking['start_datetime'])));
$inputDateTimestamp = strtotime($context['date']);
$bookedStartTime = strtotime(date('H:i', strtotime($booking['start_datetime'])));
$bookedEndTime = strtotime(date('H:i', strtotime($booking['end_datetime'])));
$userStartTime = strtotime(date('H:i', strtotime($context['start_datetime'])));
$userEndTime = strtotime(date('H:i', strtotime($context['end_datetime'])));
if( $bookedDateTimestamp == $inputDateTimestamp) {
if( $userEndTime <= $bookedStartTime || $userStartTime >= $bookedEndTime) {
echo 'i am booked';
}
}
}
it's not working.
Let's assume the user date/time is formatted like so:
$date = '2012-11-22';
$startTime = '01:00'; // note the extra '0' in front
$endTime = '04:00';
$userStartTime = "$date $startTime";
$userEndTime = "$date $endTime";
Finding overlaps is done this way:
$overlaps = 0;
foreach ($block as $block) {
if ($userStartTime < $block['end_datetime'] && $userEndTime > $block['start_datetime']) {
++$overlaps;
}
}
// if $overlaps > 0 -> there's a booking in the way
This is basically taking a non-overlap condition like this:
$userEndTime <= $block['start_datetime'] || $userStartTime >= $block['end_datetime']
And simply swap the conditions.
This can easily be written into SQL as well to reduce the network overhead between database and application.
Check this out... and modify it according to your requirement to match all existing time... I've matched only one for you...
$date = '2012-11-22';
$startTime = '2:30';
$endTime = '4:00';
$existing[] =
array
(
'id' => 1,
'start_datetime' => '2012-11-22 02:30:00',
'end_datetime' => '2012-11-22 05:00:00'
);
$UserStartTime = strtotime($date." ".$startTime);
$UserEndTime = strtotime($date." ".$endTime);
$ExistingStartTime = strtotime($existing[0]['start_datetime']);
$ExistingEndTime = strtotime($existing[0]['end_datetime']);
if($UserStartTime >= $ExistingStartTime && $UserEndTime <= $ExistingEndTime)
{
echo "BOOKED";
}
else
{
echo "NOT BOOKED";
}
Since the existing array comes from a SQL query:
$date = '2012-11-22';
$startTime = '1:00';
$endTime = '4:00';
if(strlen($startTime==4)){$startTime="0".$startTime;}
if(strlen($endTime==4)){$endTime="0".$startTime;}
$query="SELECT id FROM table WHERE start_datetime='$date $startTime:00' OR end_datetime='$date $endtimeTime:00'";
If the query returns something, the id returned have it booked!
If you want to know if any of the db info matches both datetimes just replace the OR with a AND.
If you want to know if the user time period is between any of the entries of the DB:
$query="SELECT id FROM table WHERE (start_datetime>='$date $startTime:00' AND start_datetime<='$date $endTime:00') OR (end_datetime<='$date $starttimeTime:00' AND end_datetime>='$date $endtimeTime:00') OR (start_datetime<='$date $startTime:00' AND end_datetime>='$date $starttimeTime:00')";
This may help you
$date = '2012-11-22';
$startTime= '1:00:00'; // padded two zero
$endTime = '4:00:00'; // padded two zero
$start_datetime = $date. " ".(strlen(intval(substr($startTime,0,2))) > 1 ? $startTime : "0".$startTime);
$end_datetime = $date. " ".(strlen(intval(substr($endTime,0,2))) > 1? $endTime : "0".$endTime);
for($i = 0;$i<count($your_array);$i++)
{
if($your_array[$i]['start_datetime'] == $start_datetime)
{
// Start date Found
}
if($your_array[$i]['end_datetime'] == $end_datetime)
{
// Start end Found
}
}

Identify Clash from Day and Time Array

I have checked other SO questions but can't seem to find anything related to this - point me in the right direction if I missed something.
I currently have the following array containing a day and time (requested meeting time):
Array (
[0] =>
day => 'Thursday',
start_time => '14:00',
end_time => '15:00'
[1] =>
day => 'Thursday',
start_time => '16:30',
end_time => '17:30'
)
The user is required to attend both of these times. What I am attempting to do is compare against another array containing a users current appointments and detect if there is a clash / time overlap issue
Array (
[0] =>
day => 'Monday',
start_time => '09:00',
end_time => '13:00'
[1] =>
day => 'Wednesday',
start_time => '10:45',
end_time => '11:15'
[2] =>
day => 'Thursday',
start_time => '16:45',
end_time => '17:45'
)
Using the above example I want to identify there is a clash with the second timeslot [1] => of the first array (proposed meetings) which clashes with the third timeslot [2] => of the second array (current meetings).
I have seen examples with timestamps and full dates, but not just days and start / end times.
If they are all in a database, a query for conflicts could look like:
SELECT `plan`.*
FROM `plan`
JOIN `current` ON `plan`.`day`=`current`.`day`
WHERE
`plan`.`start_time` < `current`.`end_time`
AND `plan`.`end_time` > `current`.`start_time`
where current is the table with the current schedule and plan is the table with the user's schedule. I haven't tested this just because I don't have an example, but this should return rows where the day is the same and plan times overlap current times.
edit: You might also want to do stuff like mark current as tentative if they are not required. you can put that into the query where clause.
Also the > and < mean that the start and end minute are not inclusive. so if one ends at the same time as another begins, this will not flag them as a conflict. If you want the start/end minute to be inclusive, change them to >= and <=.
You can do it this way
$slot1 = Array (
0 => array (
'day' => 'Thursday',
'start_time' => '14:00',
'end_time' => '15:00'
),
1 => array (
'day' => 'Thursday',
'start_time' => '16:30',
'end_time' => '17:30'
)
);
$slot2 = Array (
0 => array (
'day' => 'Monday',
'start_time' => '09:00',
'end_time' => '13:00'
),
1 => array (
'day' => 'Wednesday',
'start_time' => '10:45',
'end_time' => '11:15'
),
2 => array (
'day' => 'Thursday',
'start_time' => '16:45',
'end_time' => '17:45'
)
);
echo "<pre>";
$format = "l H:s";
foreach($slot1 as $value)
{
$slot1Start = DateTime::createFromFormat ($format , $value ['day'] . " " . $value['start_time'] );
$slot1End = DateTime::createFromFormat ( $format , $value ['day'] . " " . $value['end_time'] );
foreach($slot2 as $value2)
{
$slot2Start = DateTime::createFromFormat ( $format , $value2 ['day'] . " " .$value2['start_time'] );
$slot2End = DateTime::createFromFormat ( $format , $value2 ['day'] . " " .$value2 ['end_time'] );
if ($slot1Start <= $slot2End && $slot1End >= $slot2Start) {
echo sprintf ( "Even Overlap on %s %s-%s AND %s %s-%s", $value ['day'], $value ['start_time'], $value ['end_time'],
$value2 ['day'], $value2 ['start_time'], $value2 ['end_time'] ), PHP_EOL;
}
}
}
Output
Even Overlap on Thursday 16:30-17:30 AND Thursday 16:45-17:45
There are your a bit modified arrays code
$current_sheduler = Array (
[0] =>
day => 'Thursday',
start_time => '14:00',
end_time => '15:00'
[1] =>
day => 'Thursday',
start_time => '16:30',
end_time => '17:30'
)
$user_plans = Array (
[0] =>
plan_name => 'event1',
day => 'Monday',
start_time => '09:00',
end_time => '13:00'
[1] =>
plan_name => 'event2',
day => 'Wednesday',
start_time => '10:45',
end_time => '11:15'
[2] =>
plan_name => 'event3',
day => 'Thursday',
start_time => '16:45',
end_time => '17:45'
)
Here is way to process your arrays and catches if event planned by user matches time from your first array
foreach($user_plans as $plan){
foreach($current_sheduler as current){
if($plan['day']==$current['day']){
if(
($plan['start_time']>=$current['start_time']) &&
($plan['end_time']<=$current['end_time'])
){
echo "Event {$plan['plan_name']} is working now!";
}
}
}
}
This is general logic, for situation, when match means full period match only.
Another notice: befor compare times, you need to recount them into counted minutes format.

Categories