PHP - Get associative array value by date range without loop - php

I'm using the following PHP code to show a different text (just one) every week:
<?php
$items = [
[
'start' => '2020-02-03',
'end' => '2020-02-09',
'html' => 'Text #1'
],
[
'start' => '2020-02-10',
'end' => '2020-02-16',
'html' => 'Text #2'
],
[
'start' => '2020-02-17',
'end' => '2020-02-23',
'html' => 'Text #3'
],
];
$currentDate = date('Y-m-d');
foreach ($items as $item) {
if ($currentDate >= $item[start] && $currentDate <= $item[end]) echo $item[html];
}
It works.
But is there a better (i.e. cleaner, faster) way to achieve the same result? Is loop really necessary?
Thanks.
UPDATE
Inspired by Progrock's answer (which I thank), I would modify my code as follows:
$items =
[
'06' => 'Text #1',
'07' => 'Text #2',
'08' => 'Text #3',
'09' => 'Text #4'
];
$date = new DateTime(date('Y-m-d'));
echo $items[$date->format('W')];
I think it's a better solution (for what I need).

As your ranges are monday->sunday you could use ISO-8601 week numbering. Though here the data is harder to interpret without comments.
<?php
$items =
[
'06' => 'Text #1',
'07' => 'Text #2',
'08' => 'Text #3'
];
$iso_week = date('W', strtotime('2020-02-12'));
echo $items[$iso_week];
Output:
Text #2

https://www.php.net/manual/en/function.array-filter.php
$currentDate = date('Y-m-d');
$filteredItems = array_filter($items, function($item) use ($currentDate) {
return $currentDate >= $item['start'] && $currentDate <= $item['end'];
});
Though, you're still going to have to loop the filtered items for output, eventually.

Related

Grabbing information between 2 dates in php

I have an array that looks something like this
$data =
[
[
'date' => '2020-10-01',
'product' => 'Product 1',
'description' => 'Product 1',
],
[
'date' => '2020-11-01',
'product' => 'Product 2',
'description' => 'Product 2',
],
[
'date' => '2020-12-01',
'product' => 'Product 3',
'description' => 'Product 3',
],
[
'date' => '2021-01-01',
'product' => 'Product 4',
'description' => 'Product 4',
]
];
And what I would like to do is grab all the information between 2 dates.
For example I want everything between 2021-01-01 and 2020-11-01 and it would then display Product 2, Product 3 and Product 4
I'm not sure how to go about this
<?php
$data =
[
[
'date' => '2020-10-01',
'product' => 'Product 1',
'description' => 'Product 1',
],
[
'date' => '2020-11-01',
'product' => 'Product 2',
'description' => 'Product 2',
],
[
'date' => '2020-12-01',
'product' => 'Product 3',
'description' => 'Product 3',
],
[
'date' => '2021-01-01',
'product' => 'Product 4',
'description' => 'Product 4',
]
];
$from = new DateTime('2020-11-11');
$to = new DateTime('2030-10-13');
foreach ($data as $d){
$productDate = new DateTime($d['date']);
if (($productDate >= $from) && ($productDate <= $to)){
echo "is between";
var_dump($d);
}
}
In case you want to do this in PHP you can create a similar function to SQL's WHERE ... BETWEEN ... AND ... using array_filter.
If you have access to the SQL query then probably you want to have the DBMS take care of this as #RiggsFolly mentioned in the comments.
$lowerBound = strtotime('2020-11-01');
$upperBound = strtotime('2021-01-01');
$result = array_filter($data, function ($item) use ($lowerBound, $upperBound) {
$itemDate = strtotime($item['date']);
return $lowerBound <= $itemDate && $itemDate <= $upperBound;
});
echo '<pre>';
print_r($result);
echo '</pre>';
As per the comments if the data is originally sourced from a database query it's a much better idea to limit the content there, for example:
// SQL query to be used in a prepared statement
SELECT date, product, description
FROM products
WHERE date >= ?
AND date <= ?
However, failing that, the key thing here is that the dates are all properly formatted: timetamps follow the pattern Y-m-d which means that both the chronological and alphabetical order are the same
Generally...
Start ===> End
A ===> Z
1 ===> 10
0000-00-00 ===> 9999-99-99
Which means...
2020-12-30 < 2020-12-31 < 2021-01-01
That being the case when we compare two properly formatted dates (in the same format) we have no need to alter the data type/format; converting the string with DateTime or strtotime adds nothing except ~10x the required time compared to comparing the values in string format.
Anyway, comparing the dates:
Using array_filter
$minDate = '2020-11-01';
$maxDate = '2021-01-01';
$result = array_filter($data, function ($item) use ($minDate, $maxDate) {
return $minDate <= $item["date"] && $item["date"] <= $maxDate;
});
Using foreach
$minDate = '2020-11-01';
$maxDate = '2021-01-01';
$result = [];
foreach($data as $item){
if($minDate <= $item["date"] && $item["date"] <= $maxDate){
$result[] = $item;
}
}

Input multiple time range then return all another time range

I'm finding a solution that when I input a time range (or many time ranges) as an array, then it will return all another time ranges except the time range that I inputted.
For example:
I input [ 0 => ['start' => '8:30:00', 'end' => '9:00:00'], 1 => ['start' => '11:30:00', 'end' => '12:30:00']]
(8:30:00 - 9:00:00), (11:30:00 - 12:30:00)
And all the time I want to receive from 8:00:00 to 17:00:00
The expected output that I want it returns is:
[ 0 => ['start' => '8:00:00', 'end' => '8:30:00'], 1 => ['start' => '09:00:00', 'end' => '11:30:00'], 2 => ['start' => '12:30:00', 'end' => '17:00:00']]
(8:00:00 - 8:30:00), (09:00:00 - 11:30:00), (12:30:00 - 17:00:00)
Thank you.
You can simple use this concept. You dont need to use any datetime library or any other concept. Just paly with for loop will work fine.
<?php
$startingTime = '8:00:00';
$endingTime = '1:00:00';
$time = [ ['start' => '8:30:00', 'end' => '9:00:00'],
['start' => '11:30:00', 'end' => '12:30:00']];
$output = [];
for ($x = 0; $x <= count($time); $x++) {
$t = $time[$x];
$interval = [];
$interval['start'] = $startingTime;
$interval['end'] = ($t['start']=== NULL? $endingTime: $t['start'] );
array_push($output,$interval);
$startingTime = $t['end'];
}
print_r($output);
$aInputDate = [['start' => '08:30:00', 'end' => '09:00:00'],
['start' => '11:30:00', 'end' => '12:30:00']];
$sStartTime = strtotime(date('Y-m-d 08:00:00'));
$sEndTime = strtotime(date('Y-m-d 17:00:00'));
while ($sStartTime <= $sEndTime) {
$aAllTime[] = date('H:i:s', $sStartTime);
$sStartTime = strtotime('+30 minutes', $sStartTime);
}
foreach ($aInputDate as $key => $value) {
$iStartKey = array_search($value['start'], $aAllTime);
unset($aAllTime[$iStartKey]);
$iStartKey = array_search($value['end'], $aAllTime);
unset($aAllTime[$iStartKey]);
}
var_dump($aAllTime);

How to create a new array with keys based on calculated values of another array?

I have an array $post of the following format
$post[0] = [
'id' => '103',
'date' => '2016-04-17 16:30:12',
'desc' => 'content description'
];
$post[1] = [
'id' => '102',
'date' => '2016-04-17 12:30:12',
'desc' => 'content description'
];
$post[2] = [
'id' => '101',
'date' => '2016-04-17 10:30:12',
'desc' => 'content description'
];
$post[3] = [
'id' => '100',
'date' => '2016-04-16 08:30:12',
'desc' => 'content description'
];
I would like to use strtotime(date) from the $post as an unique array key, and create:
$summary['day-of-2016-04-17'] = [
'counts' => '3'
];
$summary['day-of-2016-04-16'] = [
'counts' => '1'
];
Where counts is the number of occurrence of the date used as the key.
I only need to keep the date itself as the unique key and time value is irrelevant.
I'll need the key value to be unix timestamp for further processing.
How can I implement this in the most efficient way?
Just use the date as key. The simplest way would be just use explode the date time, get the first fragment (which is the date), and assign it just like any normal array:
$summary = [];
foreach($post as $value) {
$dt = explode(' ', $value['date']); // break the date
$day_of = "day-of-{$dt[0]}"; // create the naming key
if(!isset($summary[$day_of])) { // initialize
$summary[$day_of]['counts'] = 0;
}
$summary[$day_of]['counts']++; // increment
}

Sorting array based on date/time

I am trying to sort a multidimensional array based on date/time, however it doesn't seem to be working correctly when I do a print_r. My best guess is that the time I provided to strtotime() is not in the correct format however the date and time formats are both listed, but separately in the php manual and no errors are thrown.
The format I use is unclear in the code so here it is: yyyy-mm-dd hhmm (24h with no colon GMT)
Here is the code:
function dateSort($a, $b){
$d1 = strtotime($a['date'].' '.$a['startTime']);
$d2 = strtotime($b['date'].' '.$a['startTime']);
return $d1 - $d2;
}
usort($events, 'dateSort');
print_r($events);
IVAO.
You had a typo in third line of snippet. Second line refers to $a, but in 3rd you mix both $b and $a :).
Also, I think, you needn't use strtotime at all. Look into snippet:
<?php
function dateSort($a, $b)
{
$d1 = floatval(str_replace('-', '', $a['date']) . " $a[startTime]");
$d2 = floatval(str_replace('-', '', $b['date']) . " $b[startTime]");
return $d1 - $d2;
}
$events = [
['date' => '2015-05-01', 'startTime' => '2300', 'value' => 'Event 1'],
['date' => '2012-05-01', 'startTime' => '1430', 'value' => 'Event 2'],
['date' => '2011-09-17', 'startTime' => '1021', 'value' => 'Event 3'],
['date' => '2001-01-22', 'startTime' => '0959', 'value' => 'Event 4'],
['date' => '1999-02-05', 'startTime' => '1740', 'value' => 'Event 5'],
];
usort($events, 'dateSort');
echo '<pre>' . print_r($events, 1) . '</pre>';
And click to codepad.
From Php manual, you can try to update your dateSort() function
function dateSort($a, $b){
$d1 = strtotime($a['date'].' '.$a['startTime']);
$d2 = strtotime($b['date'].' '.$a['startTime']);
return ($d1 < $d2) ? -1 : 1;
}
Suggest you to give us some of your output, easier to take it from there.

Merge array elements within time range - how?

I have an array that contain user's activities on the website. It contains activities such as writing comments, news and groups. If two comments (or more) from different users have been written within an hour, I would like to gather those two arrays into one: User and 2 more commented on X. The code I have so far looks like this:
<?php
$output = array();
$output[] = array('userID' => 12, 'txt' => sprintf('%s commented in %s', 'User1', 'Event'), 'date' => 1393080072);
$output[] = array('userID' => 13, 'txt' => sprintf('%s commented in %s', 'User2', 'Event'), 'date' => 1393080076);
$output[] = array('userID' => 13, 'txt' => sprintf('%s created the news %s', 'User2', 'RANDOMNEWS'), 'date' => 1393080080);
$output[] = array('userID' => 14, 'txt' => sprintf('%s commented in %s', 'User3', 'Event'), 'date' => 1393080088);
$date = array();
foreach($output as $k => $d) {
$date[$k] = $d['date'];
}
array_multisort($date, SORT_DESC, $output);
print_r($output);
?>
So far the code above sorts the arrays by date (DESC). Desired result: one array: %s and 2 more commented in... and the other arrays removed from output. So by taking the latest comment and checking the date from the rest of the comments, it should be possible to handle this. I simply need some suggestions.
Thanks in advance
From what I understand from your question, I think you want to find out the number of users commenting in the last hour with respect to the latest commentor.
Using your logic, array_filter can help get those values which lie in the last hour.
This is the continuation of your code -
/*
...your code...
*/
$latest_time = $output[0]['date'];
$hour_past_time = $latest_time - 3600;
$user_ids = Array();
$res=array_values(
array_filter($output,function($arr)use($latest_time, $hour_past_time,&$user_ids){
if(
$arr["date"] <= $latest_time &&
$arr["date"] >= $hour_past_time &&
in_array($arr['userID'],$user_ids) == false
){
$user_ids[] = $arr['userID'];
return true;
}
}
)
);
echo "Users with their latest comments in the past hour- <br />";
var_dump($res);
$latest_user_id = "User".$res[0]['userID'];
$rest = count($res) - 1;
echo "<br />$latest_user_id and $rest more commented.<br />";
OUTPUT -
Users with their latest comments in the past hour-
array
0 =>
array
'userID' => int 14
'txt' => string 'User3 commented in Event' (length=24)
'date' => int 1393080088
1 =>
array
'userID' => int 13
'txt' => string 'User2 created the news RANDOMNEWS' (length=33)
'date' => int 1393080080
2 =>
array
'userID' => int 12
'txt' => string 'User1 commented in Event' (length=24)
'date' => int 1393080072
User14 and 2 more commented.
Hope this helps-

Categories