I want to split the data array into three arrays - past, today, later - based on the time.
For today's array, only data with today's date and the time greater than today's time should be there.
Here's my code. There is no bug in it (as far as I know). I am getting the desired result, but I want to know if this code can be more optimized.
$current_date = date('Y-m-d');
$current_time = date('H:i:s');
foreach($data as $key => $value) {
if(date('Y-m-d', $value->meeting_scheduled_at) > $current_date) {
$calendar_data['later'][] = $value;
} elseif (date('Y-m-d', $value->meeting_scheduled_at) < $current_date
|| ( (date('Y-m-d', $value->meeting_scheduled_at) == $current_date)
&& (date('H:i:s', $value->meeting_scheduled_at) < $current_time) )
) {
$calendar_data['past'][] = $value;
} else {
$calendar_data['now'][] = $value;
}
}
$value->meeting_scheduled_at is in timestamp
EDIT: I am using this in a Laravel project.
So, if the meeting is scheduled at today's date, and time is evening 6 PM. It will come into today array till the 6 PM. After 6 PM, it goes into the past array. In short, nothing should be there in later array, unless and until it is next day.
I like to use the DateTime class for this kinda thing. It takes into account daylight savings etc and can be compared really easily.
$now = new DateTime();
$tomorrow = new DateTime();
$meetingDate = new DateTime();
$tomorrow->add(new DateInterval('P1D'))->setTime(0,0,0);
foreach ($data as $key => $value) {
$meetingDate->setTimestamp($value->meeting_scheduled_at);
// if $value->meeting_scheduled_at format YYYY-MM-DD then
// we'd create the $meetingDate object here like this
// $meetingDate = new DateTime($value->meeting_scheduled_at);
if ($meetingDate < $now) {
$calendar_data['past'][] = $value;
} else if ($meetingDate >= $tomorrow) {
$calendar_data['later'][] = $value;
} else {
$calendar_data['now'][] = $value;
}
}
date('Y-m-d', $value->meeting_scheduled_at) should be calculated only once before you use its result in the conditions.
Make it easier
$now = time();
// Midnight due to discussion with Kevin Nagurski in comments :)
$tommorow = strtotime('tomorrow');
foreach($data as $key => $value)
if ($value->meeting_scheduled_at) < $now) $calendar_data['past'][] = $value;
elseif ($value->meeting_scheduled_at) >= $tommorow) $calendar_data['later'][] = $value;
else $calendar_data['now'][] = $value;
You can use timestamp instead.
$now = time();
$today_limt = strtotime("today 6 PM");
foreach($data as $key => $value) {
$meeting_time = strtotime($value->meeting_scheduled_at);
if($meeting_time > $today_limit) {
$calendar_data['later'][] = $value;
} elseif($meeting_time < $now) {
$calendar_data['past'][] = $value;
} else {
$calendar_data['now'][] = $value;
}
}
Related
Let's say I have an array called $selectedDates containing the following
$selectedDates = [
"2000-01-31",
"2000-02-01",
"2000-02-02",
"2000-02-20"
];
Is there some way in PHP to calculate out what # each day is consecutively.
So that the first one returns 1, the 2nd one would be returning 2, the 3rd would be 3 but the 4th would be 1 again.
I'm trying to loop through them all at the moment but am not really getitng anywhere.
<?php foreach ($selectedDates as $date): ?>
Seriously lost about what to put here.
<?php echo $consecDayCount; ?>
<?php endforeach; ?>
I'm thinking inside of the loop I may need to loop through it again? And start at the first one and check each day going up one more, adding to some incrementer for each day that says the previous date in the array was the previous day in time. I'm just kind of banging my head against a wall figuring out that part.
One way to Rome...
# We assume $selectedDates is sorted at this point.
$selectedDates = [
"2000-01-31",
"2000-02-01",
"2000-02-02",
"2000-02-20"
];
# The array we will print.
$coll = array();
# We use array_reverse to start from the last entry.
foreach(array_reverse($selectedDates) as $date) {
$tmp = $date;
$con = 1;
do $tmp = date('Y-m-d', strtotime("$tmp -1day"));
# ++$con is used to count only up if in_array gives true.
while(in_array($tmp, $selectedDates) && (++$con));
$coll[$date] = $con;
}
print_r($coll);
Result: Array ( [2000-02-20] => 1 [2000-02-02] => 3 [2000-02-01] => 2 [2000-01-31] => 1 )
Here you go:
$selectedDates = [
'2000-01-31',
'2000-02-01',
'2000-02-02',
'2000-02-20',
'2000-02-21',
];
$format = 'Y-m-d';
$consecutive = [];
$length = count($selectedDates);
$streak = false;
$last = null;
for($index = 0; $index < $length - 1; $index++) {
$firstDate = DateTime::createFromFormat($format, $selectedDates[$index]);
$secondDate = DateTime::createFromFormat($format, $selectedDates[$index + 1]);
$diff = $firstDate->diff($secondDate);
if ($diff->days === 1) {
// consecutive dates
if ($streak) {
$consecutive[$last]++; // we have another consecutive day to the current streak
} else {
$consecutive[$selectedDates[$index]] = 2; // we already have 2 consecutive days
$last = $selectedDates[$index];
$streak = true;
}
} else {
$streak = false;
}
}
var_dump($consecutive);
This will give you an array in the date => number of consecutive days starting on that date format.
Another way
$dates = array(
new DateTime('2000-01-31'),
new DateTime('2000-02-01'),
new DateTime('2000-02-02'),
new DateTime('2000-02-20'),
);
// process the array
$lastDate = null;
$ranges = array();
$currentRange = array();
foreach ($dates as $date) {
if (null === $lastDate) {
$currentRange[] = $date;
} else {
// get the DateInterval object
$interval = $date->diff($lastDate);
// DateInterval has properties for
// days, weeks. months etc. You should
// implement some more robust conditions here to
// make sure all you're not getting false matches
// for diffs like a month and a day, a year and
// a day and so on...
if ($interval->days === 1) {
// add this date to the current range
$currentRange[] = $date;
} else {
// store the old range and start anew
$ranges[] = $currentRange;
$currentRange = array($date);
}
}
// end of iteration...
// this date is now the last date
$lastDate = $date;
}
// messy...
$ranges[] = $currentRange;
// print dates
foreach ($ranges as $range) {
// there'll always be one array element, so
// shift that off and create a string from the date object
$startDate = array_shift($range);
$str = sprintf('%s', $startDate->format('D j M'));
// if there are still elements in $range
// then this is a range. pop off the last
// element, do the same as above and concatenate
if (count($range)) {
$endDate = array_pop($range);
$str .= sprintf(' to %s', $endDate->format('D j M'));
}
echo "<p>$str</p>";
} ?>
output::: Mon 31 Jan to Wed 2 Feb
Sun 20 Feb
I have a list of events that start and begin on different dates.
04.12.2015–03.01.2016
08.01.2016–14.02.2016
26.02.2016–27.03.2016
And I have a piece of code, that adds a current-event class for a single event if its between some dates.
$startDate = get_post_meta('_event_start_date', true);
$endDate = get_post_meta('_event_end_date', true);
$currentDate = current_time( 'mysql' );
if ( ($currentDate > $startDate) && ($currentDate < $endDate) ) {
return 'current-event';
} else {
return '';
}
This all works fine and does its job, but what I've encountered is that between two events there isn't any dates to compare. For example, if today's date is the 5th of January and the next event is starting at 8th of January, it doesn't add a current-event class to the future event. I guess I'd have to add another elseif statement to the code, but with what should I compare it with?
Just to bring out the case here, that I'd like to add the current-event class for only one future event.
I think this is what you want:
if ( ($currentDate > $startDate) && ($currentDate < $endDate) ) {
return 'current-event';
} else if($currentDate < $startDate) {
return 'current-event';
} else {
return '';
}
//version 2:
$startDate = get_post_meta('_event_start_date', true);
$endDate = get_post_meta('_event_end_date', true);
$currentDate = current_time( 'mysql' );
$startDays = array(); //assign your start days to this array & sort it as well
if ( ($currentDate > $startDate) && ($currentDate < $endDate) ) {
return 'current-event';
} else {
foreach($startDays as $day)
{
if($currentDate < $day)
{
/*
this will return current event for the exactly next event (and not for the other next events).
but make sure to sort the dates in the start days array.
*/
return 'current-event';
break;
}else
{
return '';
}
}
}
I'm trying to find the average date and guess the next one.
The input is a list of dates that looks like this:
$completeDate = array(
'2015-04-13T00:00:00-0800',
'2015-03-20T00:00:00-0800',
'2015-02-17T00:00:00-0800',
'2015-01-10T00:00:00-0800'
);
I'm trying to scan a list of x amount of dates, and output an average of the dates overall.
So in the above example I think the output would be 2015-5-15 is expected average date.
How would I tackle this?
If you're looking for the average of those dates you can simply get the day of the year for each of those dates, average them out, and use that date:
$completeDate = array(
'2015-04-13T00:00:00-0800',
'2015-03-20T00:00:00-0800',
'2015-02-17T00:00:00-0800',
'2015-01-10T00:00:00-0800'
);
$first = null;
$last = null;
foreach($completeDate as $date) {
$dayOfYear = (new DateTime($date))->format('z');
if (is_null($first)) {
$first = $last = $dayOfYear;
}
else {
if ($dt < $first) {
$first = $dayOfYear;
}
if ($dt > $last) {
$last = $dayOfYear;
}
}
}
$avg = round(($first + $last) / 2);
$averageDate = DateTime::createFromFormat('z', $avg);
echo $averageDate->format('Y-m-d'); // 2015-02-26
Demo
If your looking for the average of the day of the month for the dates in that array and then use that day of the next month, you just need to average out the days of the month and then use that with the next month:
$completeDate = array(
'2015-04-13T00:00:00-0800',
'2015-03-20T00:00:00-0800',
'2015-02-17T00:00:00-0800',
'2015-01-10T00:00:00-0800'
);
$month = 0;
$days = 0;
foreach($completeDate as $date) {
$dt = new DateTime($date);
$month_num = $dt->format('n');
if ($month_num > $month) {
$month = $month_num;
}
$days += $dt->format('j');
}
$avg = round($days / count($completeDate));
$date = new DateTime(sprintf('%d-%01d-%01d', $dt->format('Y'), ++$month, $avg));
echo $date->format('Y-m-d'); // 2015-05-15
Demo
I have an array structured like this:
Array ( [0] => 24-12-2013 [1] => 25-12-2013 [2] => 26-12-2014 [3] => 27-12-2013 [4])
I would like to check if any of the dates in the array are within a given date range.
The date range is structured like this:
$start = (date("d-m-Y", strtotime('25-12-2013')));
$end = (date("d-m-Y", strtotime('26'12'2013')));
I would like to know which dates in the array are within the date range.
Couple things:
Use timestamps or DateTime objects to compare dates, not strings
Use date format YYYY-MM-DD to avoid potential ambiguity about your date format (d/m/y or m/d/y)
This code will do what you want:
$dates = array("2013-12-24","2013-12-25","2014-12-24","2013-12-27");
$start = strtotime('2013-12-25');
$end = strtotime('2013-12-26');
foreach($dates AS $date) {
$timestamp = strtotime($date);
if($timestamp >= $start && $timestamp <= $end) {
echo "The date $date is within our date range\n";
} else {
echo "The date $date is NOT within our date range\n";
}
}
See it in action:
http://3v4l.org/GWJI2
$dates = array ('24-12-2013', '25-12-2013', '26-12-2014', '27-12-2013');
$start = strtotime('25-12-2013');
$end = strtotime('26-12-2013');
$inDateRange = count(
array_filter(
$dates,
function($value) use($start, $end) {
$value = strtotime($value);
return ($value >= $start && $value <= $end);
}
)
);
<?php
$start = DateTime::createFromFormat('d-m-Y', '25-12-2013');
$end = DateTime::createFromFormat('d-m-Y', '26-12-2013');
$dates = array('24-12-2013','25-12-2013','26-12-2014','27-12-2013');
$matches = array();
foreach ($dates as $date) {
$date2 = DateTime::createFromFormat('d-m-Y', $date);
if ($date2 >= $start && $date2 =< $end) {
$matches[] = $date;
}
}
print_r($matches);
See it in action
$_between = array();
$start = date('Ymd', strtotime($start));
$end = date('Ymd', strtotime($end));
foreach ($dates as $date)
{
$date = date('Ymd',strtotime($date));
if ($date > $start && $date < $end) {
array_push($_between,$date);
continue;
}
}
echo '<pre>';
var_dump($_between);
echo '</pre>';
Loop over the array turning each date into unix time (seconds since Jan 1, 1970), and do simple math to see if the number of seconds is between the range. Like so:
$start = strtotime('25-12-2013');
$end = strtotime('26'12'2013');
foreach($date in $dates) {
$unix_time = strtotime($date);
if($unix_time > $start && $unix_time < $end)
//in range
}
// PHP >= 5.3:
$dates_in_range = array_filter($array, function($date) {
global $start;
global $end;
return (strtotime($date) >= strtotime($start) and strtotime($date) <= strtotime($end));
});
I have some DB entries, they have timestamps. And all I want is to draw a separate line between days. And also, I need the day to start not at 00:00, but at 07:00. It's like an offset for the day start.
Now I have that (for context):
foreach($logs as $log) {
$cur_date = $log[0]['timestamp'];
echo "<p>".$log[0]['content']."</p>";
}
Is there a simple workaround for the problem I've described?
Thank you!
$prev_date = 0;
foreach($logs as $log) {
$cur_date = strtotime($log[0]['timestamp']);
$cur_day_beginning = strtotime(date("Y-m-d 07:00:00", $cur_date));
if ($cur_date >= $cur_day_beginning && $prev_date < $cur_day_beginning) {
echo "<hr/>";
}
$prev_date = $cur_date;
echo "<p>".$log[0]['content']."</p>";
}