Check if time interval does fall inside other time intervals - php

I want to determine if given interval doesn't fall inside other intervals (using 24-hour clock format), here is the example:
case1:
$startDate = '2021-04-05 08:05:00';
$endDate = '2021-04-05 10:05:00';
$intervals = [['startDate' => '2021-04-05 08:30:00', 'endDate' => '2021-04-05 11:05:00'], ['startDate' => '2021-04-05 12:30:00', 'endDate' => '2021-04-05 13:05:00']]
In this case we should set:
$flagCanSchedule = 0;
Because 2021-04-05 08:05:00 to 2021-04-05 10:05:00 falls between this interval:
'startDate' => '2021-04-05 08:30:00', 'endDate' => '2021-04-05
11:05:00'
But for this:
case 2:
$startDate = '2021-04-05 08:05:00';
$endDate = '2021-04-05 10:05:00';
$intervals = [['startDate' => '2021-04-05 10:05:00', 'endDate' => '2021-04-05 11:05:00'], ['startDate' => '2021-04-05 07:30:00', 'endDate' => '2021-04-05 08:05:00']]
In this case set:
$flagCanSchedule = 1;
Because we don't overlap any other interval, evan tho ('2021-04-05 08:05:00' == '2021-04-05 08:05:00').
I wanted to solve this using strtotime and transform the dates to unix format, but I'm not sure how to write my if statement.
$startDate = strtotime('2021-04-05 08:05:00');
$endDate = strtotime('2021-04-05 10:05:00');
foreach($intervals as $interval) {
if($startDate <= strtotime($interval['startDate']) && $endDate <=
strtotime($interval['endDate'])) {
$flagCanSchedule = 1;
} else {
$flagCanSchedule = 0;
}
}

You should add a break when a flagCanSchedule is found. Because, the next iterations overrides this value (from 1 to 0).
$intervals = [
['startDate' => '2021-04-05 10:05:00', 'endDate' => '2021-04-05 11:05:00'],
['startDate' => '2021-04-05 07:30:00', 'endDate' => '2021-04-05 08:05:00'],
];
$startDate = strtotime('2021-04-05 08:05:00');
$endDate = strtotime('2021-04-05 10:05:00');
foreach($intervals as $interval)
{
if ($startDate <= strtotime($interval['startDate']) &&
$endDate <= strtotime($interval['endDate']))
{
$flagCanSchedule = 1;
break; // << stop the test
}
else {
$flagCanSchedule = 0;
}
}
var_dump($flagCanSchedule); // int(1)
You also can remove the else statement by initializing the flag first.
$flagCanSchedule = 0;
foreach ($intervals as $interval)
{
if ($startDate <= strtotime($interval['startDate']) &&
$endDate <= strtotime($interval['endDate']))
{
$flagCanSchedule = 1;
break;
}
}
var_dump($flagCanSchedule); // int(1)

Related

PHP: Get the sum of a different dates in array

Hello Im just a beginner programmer but Im now building an app which gets the total hours of work.
Here I have a time_start array which the threshold for the customer to in and same as out for time_end
The logs here is where the person checks in.
$time_start = [
[0] => '22:00:00',
[1] => '03:00:00',
];
$time_end = [
[0] => '02:00:00',
[1] => '08:00:00',
];
$logs = [
[0] => '2019-07-09 22:00:00',
[1] => '2019-07-10 02:00:00',
[2] => '2019-07-10 03:00:00',
[3] => '2019-07-10 08:00:00',
];
So I'm trying to get the sum of their hours in night shift which has different date.
Im trying to get it in:
foreach( $logs as $check_time ){
$attendance_date_time = date("Y-m-d",strtotime($check_time));
$time_starts = date('Y-m-d H:i:s', strtotime("$attendance_date_time $time_start"));
$time_ends = date('Y-m-d H:i:s', strtotime("$attendance_date_time $time_end"));
if ( $check_time >= $time_starts && $check_time <= $time_ends )
{
$time[] = $check_time;
}else{
$time = null
}
}
Supposedly I will get all logs because it is between time_start and time_end and store it to $time
And summing the time i get.
Since I'm new at php is their any easiest idea to get the total work hours? Cuz I get a null because the time_end it gets was the date of check_in.
Here is your snippet,
$time_start = [
0 => '22:00:00',
1 => '03:00:00',
];
$time_end = [
0 => '02:00:00',
1 => '08:00:00',
];
$logs = [
0 => '2019-07-09 22:00:00',
1 => '2019-07-10 02:00:00',
2 => '2019-07-10 03:00:00',
3 => '2019-07-10 08:00:00',
];
$time = [];
$diff = 0;
for ($j = 0; $j < count($logs); $j = $j + 2) {
$attendance_start = date("Y-m-d", strtotime($logs[$j]));
$attendance_end = date("Y-m-d", strtotime($logs[$j + 1]));
for ($i = 0; $i < count($time_start); $i++) {
$time_starts = date('Y-m-d H:i:s', strtotime("$attendance_start " . $time_start[$i] . ""));
$time_ends = date('Y-m-d H:i:s', strtotime("$attendance_end " . $time_end[$i] . ""));
if ($logs[$j] >= $time_starts && $logs[$j + 1] <= $time_ends) {
array_push($time, $logs[$j], $logs[$j + 1]);
// calculating diff for two alternate days
$diff += (round((strtotime($logs[$j + 1]) - strtotime($logs[$j])) / 3600, 1));
break;
}
}
}
echo $diff . " Hours";die;
Demo
Output:-
9 Hours
The for loop is the easiest way to do this
$time_start = [
'22:00:00',
'03:00:00',
];
$time_end = [
'02:00:00',
'08:00:00',
];
$logs = [
'2019-07-09 22:00:00',
'2019-07-10 02:00:00',
'2019-07-10 03:00:00',
'2019-07-10 08:00:00',
];
$totalDiff = 0;
for($i =0 ; $i < count($logs); $i = $i + 2)
{
$startDate = strtotime($logs[$i]);
$endDate = strtotime($logs[$i+1]);
$diff = $endDate-$startDate;
$totalDiff += $diff;
}
$hourDiff = $totalDiff / 3600;
echo $hourDiff . ' hours';
Demo

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?

PHP - Date range by month

I have a date range and I need it to group by month but I want to keep starting day and ending day. So far I have this:
$interval['from'] = '2017-01-02 00:00:00';
$interval['to'] = '2017-02-06 23:59:59';
$start = Carbon::createFromFormat('Y-m-d H:i:s', $interval['from'])->startOfMonth();
$end = Carbon::createFromFormat('Y-m-d H:i:s', $interval['to'])->startOfMonth()->addMonth();
$separate = CarbonInterval::month();
$period = new \DatePeriod($start, $separate, $end);
foreach ($period as $dt) {
dump($dt);
}
But as result I'm getting:
Carbon\Carbon(3) {
date => "2017-01-01 00:00:00.000000" (26)
timezone_type => 3
timezone => "Europe/Prague" (13)
}
Carbon\Carbon(3) {
date => "2017-02-01 00:00:00.000000" (26)
timezone_type => 3
timezone => "Europe/Prague" (13)
}
It is grouped by month but I need to get whole month period, I mean from
2017-01-02 00:00:00 to 2017-01-31 23:59:59
2017-02-01 00:00:00 to 2017-02-06 23:59:59.
Output:
$array = [
0 => [
'from' => '2017-01-02 00:00:00',
'to' => '2017-01-31 23:59:59'
],
1 => [
'from' => '2017-02-01 00:00:00',
'to' => '2017-02-06 23:59:59'
]
];
What is the easiest way to achive it?
Edit: Here is a little bit modified Carbon version of accepted answer, maybe somebody will need it:
$interval['from'] = '2017-01-02 00:00:00';
$interval['to'] = '2017-04-08 23:59:59';
$interval_from = Carbon::createFromFormat('Y-m-d H:i:s', $interval['from']);
$interval_to = Carbon::createFromFormat('Y-m-d H:i:s', $interval['to']);
$result = [];
foreach (range($interval_from->month, $interval_to->month) as $x) {
$to = $interval_from->copy()->endOfMonth();
if ($x == $interval_to->month) {
$result[] = ["from" => $interval_from, "to" => $interval_to];
} else {
$result[] = ["from" => $interval_from, "to" => $to];
}
$interval_from = $to->copy()->addSecond();
}
PHP code demo
Try this solution you can change from one month to another month(not year) and then check. Lengthy solution but hopefully works correctly, putting explaination.
<?php
ini_set('display_errors', 1);
$from=$interval['from'] = '2017-01-02 00:00:00';
$interval['to'] = '2017-03-07 23:59:59';
$month1=date("m", strtotime($interval['from']));
$month2=date("m", strtotime($interval['to']));
$result=array();
foreach(range($month1, $month2) as $x)
{
$dateTimeObj= new DateTime($from);
$dayDifference=($dateTimeObj->format('d')-1);
$dateTimeObj= new DateTime($from);
$dateTimeObj->add(new DateInterval("P1M"));
$dateTimeObj->sub(new DateInterval("P".$dayDifference."DT1S"));
$to= $dateTimeObj->format("Y-m-d H:i:s");
if($x==$month2)
{
$dateTimeObj= new DateTime($interval['to']);
$noOfDays=$dateTimeObj->format("d");
$dateTimeObj->sub(new DateInterval("P".($noOfDays-1)."D"));
$from=$dateTimeObj->format("Y-m-d H:i:s");
$result[]=array("from"=>$from,"to"=>$interval['to']);
}
else
{
$result[]=array("from"=>$from,"to"=>$to);
}
//adding 1 second to $to for next time to be treated as $from
$dateTimeObj= new DateTime($to);
$dateTimeObj->add(new DateInterval("PT1S"));
$from= $dateTimeObj->format("Y-m-d H:i:s");
}
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;
}

Logo change with date script

I just wondered if anybody can point me in the right direction: I'm looking to make a script whereby the logo on my site changes depending on the date; so for instance a haloween style one soon.
I started off by having 2 arrays, 1 of start dates and 1 of end dates(not sure even if this is the best way!):
<?php
$start_dates = array('01/01' => 'New Years',
'14/02' => 'Valentine Day',
'16/02/2010' => 'Pancake Day',
'17/03' => 'St Patricks Day',
'01/04' => 'April Fools',
'02/04/2010' => 'Easter',
'23/04' => 'St Georges Day',
'11/06/2010' => 'World Cup',
'31/10' => 'Halloween',
'05/11' => 'Guy Fawkes',
'11/11' => 'Armistice Day',
'16/10' => 'Today',
'15/12' => 'Christmas');
$end_dates = array( '08/01' => 'New Years',
'15/02' => 'Valentine Day',
'17/02/2010' => 'Pancake Day',
'18/03' => 'St Patricks Day',
'02/04' => 'April Fools',
'06/04/2010' => 'Easter',
'24/04' => 'St Georges Day',
'12/07/2010' => 'World Cup',
'01/11' => 'Halloween',
'06/11' => 'Guy Fawkes',
'12/11' => 'Armistice Day',
'17/10' => 'Today',
'01/01' => 'Christmas');
?>
Easy so far...the problemis that I need a way of working out if todays date falls between the start date and end date, then changing the image file name.
Its a long shot but I hope someone would be kind enough to help.
Thanks,
B.
like this
$events = array(
'New Year' => '01/01 01/08',
'Pancake Day' => '16/02/2010 17/02/2010',
//etc
);
echo find_event($events, '16/02');
where find_event() is
function mdy2time($date) {
$e = explode('/', $date);
if(count($e) < 3)
$e[] = '2010';
return strtotime("$e[1]-$e[0]-$e[2]");
}
function find_event($events, $date = null) {
$date = is_null($date) ? time() : mdy2time($date);
foreach($events as $name => $range) {
list($start, $end) = explode(' ', $range);
if($date >= mdy2time($start) && $date <= mdy2time($end))
return $name;
}
return null;
}
you should use an array more like this:
$dates = array();
$dates[] = array(
'name' => 'New Years'
'start' = '01/14',
'end' => '01/20',
'style' => 'haloween',
);
$dates[] = array(
//...
);
then you can get the style as follows:
$style='default';
// date as number e.g. 130 (january 30th)
$currDate = date('md',time()) * 1;
foreach ($dates AS $k => $v) {
$tmp = explode("/",$v['start'];
$start = ($tmp[1].$tmp[0])*1;
$tmp = explode("/",$v['end'];
$stop = ($tmp[1].$tmp[0])*1;
if ($start <= $currDate && $currDate < $stop) {
$style=$v['style'];
break;
}
}
echo 'style: '.$style;
Didn't check the code yet, so feel free to correct me if iam wrong.

Categories