FOREACH with a DATE COMPARE condition (PHP) - php

I have a JSON source and I am trying to loop trough it and show some results (up to 9 results) which is not a problem
The problem is that I want to show only the results that are matching a certain date, where the date might be exact or between 2 dates.
For example I want to show only the events where let say the date 2019-11-17 is within timeFrom timeTo of the event or timeFrom or timeTo is equal to it. In that example it will be event 1 and 3
This is the source sample
{
"title":"event 1",
"timeFrom":"2019-11-16 19:00:00",
"timeTo":"2019-11-18 22:00:00",
"listText":"text of the event",
"url":"https://url",
"imageUrl":"https://image.jpg",
"locations":{
"title":"Location name",
"url":"https://location"
}
},
{
"title":"event 2",
"timeFrom":"2019-11-20 19:00:00",
"timeTo":"2019-11-20 22:00:00",
"listText":"text of the event",
"url":"https://url",
"imageUrl":"https://image.jpg",
"locations":{
"title":"Location name",
"url":"https://location"
}
},
{
"title":"event 3",
"timeFrom":"2019-11-17 19:00:00",
"timeTo":"2019-11-17 22:00:00",
"listText":"text of the event",
"url":"https://url",
"imageUrl":"https://image.jpg",
"locations":{
"title":"Location name",
"url":"https://location"
}
And this is the foreach I have at the moment
foreach(array_slice($arr, 0, 9) as $data) {
//then I will show the result
}
So, I can't figure out how to make that condition within the foreach.

This function iterates through the events data, looking for events whose from and to dates surround the given date:
function find_events($events, $date) {
$date = new DateTime($date);
foreach ($events as $event) {
$from = (new DateTime($event['timeFrom']))->setTime(0,0,0);
$to = (new DateTime($event['timeTo']))->setTime(0,0,0);
if ($date >= $from && $date <= $to) {
echo "{$event['title']} ({$event['listText']}) from {$event['timeFrom']} to {$event['timeTo']}\n";
}
}
}
$events = json_decode($json, true);
find_events($events, '2019-11-17');
Output:
event 1 (text of the event) from 2019-11-16 19:00:00 to 2019-11-18 22:00:00
event 3 (text of the event) from 2019-11-17 19:00:00 to 2019-11-17 22:00:00
Demo on 3v4l.org

Try this code:
$date = "2019-11-17";
$events = json_decode($json_output, true);
foreach ($events as $event)
{
if (($date > $event['timeFrom'] && $date < $event['timeTo']) || in_array($date, array($event['timeFrom'], $event['timeTo'])))
{
$filtered_events[] = $event;
}
}
$sliced_events = array_slice($filtered_events, 0, 9);
print_r($sliced_events);

Related

DateTime Failed to Parse Time String

I am passing 2 date and time strings per item in the array which is brought over from JSON.
These dates are successfully stored in the array but the DateTime function doesn't like them for some reason.
I have tried using different formats, just the date, just the time but nothing worked.
I have provided the JSON file and my PHP Tests file I am using.
<?php
error_reporting(E_ALL);
ini_set('display_errors', 1);
$revokes = jsonDecode(file_get_contents("../revokes.json"), true);
$certificates = $revokes['certificates'];
// Prints the revokes array
// print_r($revokes);
$dates = array();
foreach ($certificates as $certificate_key => $certificate) {
$signed = $certificate['signed'];
$revoked = $certificate['revoked'];
$dates[] = array(
"signed" => $signed,
"revoked" => $revoked
);
}
// Prints the dates
// print_r($dates);
$intervals = array();
foreach ($dates as $key) {
$newTimeAdd = new DateTime($key["signed"]);
$newTimeRead = new DateTime($key["revoked"]);
$interval = $newTimeAdd->diff($newTimeRead);
// returns 0 on all elements of the interval array.
// var_dump($interval);
$intervals[] = $interval->days;//get days
}
if(!empty($intervals)) {
$average = average($intervals);
}
// Prints nothing
// print_r($intervals);
function average($arr) {
return array_sum($arr)/count($arr);
}
function jsonDecode($json, $assoc = false)
{
$ret = json_decode($json, $assoc);
if ($error = json_last_error())
{
$errorReference = [
JSON_ERROR_DEPTH => 'The maximum stack depth has been exceeded.',
JSON_ERROR_STATE_MISMATCH => 'Invalid or malformed JSON.',
JSON_ERROR_CTRL_CHAR => 'Control character error, possibly incorrectly encoded.',
JSON_ERROR_SYNTAX => 'Syntax error.',
JSON_ERROR_UTF8 => 'Malformed UTF-8 characters, possibly incorrectly encoded.',
JSON_ERROR_RECURSION => 'One or more recursive references in the value to be encoded.',
JSON_ERROR_INF_OR_NAN => 'One or more NAN or INF values in the value to be encoded.',
JSON_ERROR_UNSUPPORTED_TYPE => 'A value of a type that cannot be encoded was given.',
];
$errStr = isset($errorReference[$error]) ? $errorReference[$error] : "Unknown error ($error)";
throw new \Exception("JSON decode error ($error): $errStr");
}
return $ret;
}
?>
{
"lifeExp": "2 Days",
"certificates": [
{
"name": "CCS Group Pte Ltd",
"signed": "22/05/2020 10:31:00",
"revoked": "23/05/2020 5:40:00",
"files": {
"p12": "certificates/:id/certificate.p12",
"pem": "certificates/:id/certificate.pem",
"key": "certificates/:id/certificate.key",
"password": "certificates/:id/certificate.password"
}
},
{
"name": "Hoola Inc",
"signed": "16/05/2020 12:40:00",
"revoked": "19/05/2020 04:00:00",
"files": {
"p12": "certificates/:id/certificate.p12",
"pem": "certificates/:id/certificate.pem",
"key": "certificates/:id/certificate.key",
"password": "certificates/:id/certificate.password"
}
}
]
}
Your date formats are in European format (DD/MM/YYYY) which means you'll need to use DateTime::createFromFormat() to specify the correct format to have DateTime handle it correctly. This is due to PHP assuming US date format when it sees the NN/NN/NNNN date format.
<?php
$json = json_decode('{
"lifeExp": "2 Days",
"certificates": [
{
"name": "CCS Group Pte Ltd",
"signed": "22/05/2020 10:31:00",
"revoked": "23/05/2020 5:40:00",
"files": {
"p12": "certificates/:id/certificate.p12",
"pem": "certificates/:id/certificate.pem",
"key": "certificates/:id/certificate.key",
"password": "certificates/:id/certificate.password"
}
},
{
"name": "Hoola Inc",
"signed": "16/05/2020 12:40:00",
"revoked": "19/05/2020 04:00:00",
"files": {
"p12": "certificates/:id/certificate.p12",
"pem": "certificates/:id/certificate.pem",
"key": "certificates/:id/certificate.key",
"password": "certificates/:id/certificate.password"
}
}
]
}', true);
$signed = $json['certificates'][1]['signed'];
$revoked = $json['certificates'][1]['revoked'];
$newTimeAdd = DateTime::createFromFormat('d/m/Y H:i:s', $signed);
$newTimeRead = DateTime::createFromFormat('d/m/Y H:i:s', $revoked);
$interval = $newTimeAdd->diff($newTimeRead);
echo $interval->days;
Output
2
Demo

PHP - join equal arrays and add count of arrays joined

I have a task on my Laravel project that runs every day and check for expiration on some coupons. If they expire that day, I add them as array to the user table to display them on the admin panel. Problem is, client wants them to be shown joined if they share date and price properties and I'm having some trouble finding the appropriate way to do this. Let me explain:
$coupons = Coupon::where([['date_end', date('Y-m-d')], ['status', '!=', 0]])->get();
foreach ($coupons as $key => $coupon)
{
$user = User::where('id', $coupon->user_id)->first();
$coupon->status = Coupon::EXPIRED;
$coupon->save();
if ($user->expired_coupons == NULL)
{
$coupons_expired = [];
}
else
{
$coupons_expired = json_decode($user->expired_coupons);
}
$last_coupon_expired['date'] = $coupon->date_end;
$last_coupon_expired['quantity'] = 1;
$last_coupon_expired['price'] = $coupon->voucher->available->price_per_meal;
$coupons_expired[] = $last_coupon_expired;
$user->expired_coupons = $coupons_expired;
$user->save();
}
And I'll get something like this in the db:
[{
"date": "2020-05-24",
"quantity": 1,
"price": 5
}, {
"date": "2020-05-24",
"quantity": 1,
"price": 5
}, {
"date": "2020-05-24",
"quantity": 1,
"price": 10
}, {
"date": "2020-05-23",
"quantity": 1,
"price": 5
}]
Which looks like this in my admin panel:
And in this case, the way I'd want it to show would be:
- 2020-05-24 || 2 || 5
- 2020-05-24 || 1 || 10
- 2020-05-23 || 1 || 5
If I didn't need the quantity I could just get rid of the arrays that are exactly equal, but everything I tried to get the thing working as I want to has failed. Any pointers? Thanks.
If it is possible to share the data what you have got $coupons variable. But i tried to solve the problem by grouping the date and price. May be there need to more improvement.
$coupons = Coupon::where([['date_end', date('Y-m-d')], ['status', '!=', 0]])->get();
$coupons_expired = [];
foreach ($coupons as $key => $coupon)
{
$user = User::where('id', $coupon->user_id)->first();
$coupon->status = Coupon::EXPIRED;
$coupon->save();
if ($user->expired_coupons == NULL)
{
$coupons_expired = [];
}
else
{
$coupons_expired = json_decode($user->expired_coupons);
}
if (isset($coupons_expired[$coupon->date_end][$coupon->voucher->available->price_per_meal])) {
$coupons_expired[$coupon->date_end][$coupon->voucher->available->price_per_meal]['quantity']++;
} else {
$coupons_expired[$coupon->date_end][] = [
$coupon->voucher->available->price_per_meal => [
'data' => $coupon->date_end,
'quantity' => 1,
'price' => $coupon->voucher->available->price_per_meal
]
];
}
$user->expired_coupons = $coupons_expired;
$user->save();
}
$mappedData = [];
foreach ($coupons_expired as $data => $dateGroups) {
foreach ($dateGroups as $qty => $coupon) {
$mappedData[] = $coupon;
}
}
I came up with this solution that, for now, meets my needs. Since the date will always be the same for the coupons that expire (being a daily task) I just create an array with all the prices and the amount of times they appear, and then iterate it to make the final array of coupons expired joined by date and price.
foreach ($coupons as $key => $coupon)
{
$coupon->status = Coupon::EXPIRED;
$coupon->save();
$expired_coupon_price['price'] = (string)$coupon->voucher->available->price_per_meal;
$expired_coupons_prices[] = $expired_coupon_price;
}
$array_prices_unique = array_count_values(array_column($expired_coupons_prices, 'price'));
foreach ($array_prices_unique as $key => $price)
{
$last_coupon_expired['date'] = date('Y-m-d');
$last_coupon_expired['quantity'] = $price;
$last_coupon_expired['price'] = (float) key($array_prices_unique);
$coupons_expired_today[] = $last_coupon_expired;
next($array_prices_unique);
}
if ($user->expired_coupons == NULL)
{
$coupons_expired_from_user = [];
}
else
{
$coupons_expired_from_user = json_decode($user->expired_coupons);
}
$user->expired_coupons = array_merge($coupons_expired_from_user,$coupons_expired_today);
$user->save();
}

php split start time and end time with merge new array

First all; I'm sorry if my question is not irrelevant. I'm new on array's with PHP.
I have an array;
[
{
"order_id":"7",
"order_start_time":"08:00:00",
"order_end_time":"11:00:00",
"order_date":"29\/03\/2018"
},
{
"order_id":"8",
"order_start_time":"10:00:00",
"order_end_time":"01:00:00",
"order_date":"29\/03\/2018"
}
]
I want to split time ranges from start to end by hours. Desired output;
[
{
"hour_selected":"08:00:00"
},
{
"hour_selected":"09:00:00"
},
{
"hour_selected":"10:00:00"
},
{
"hour_selected":"11:00:00"
},
{
"hour_selected":"12:00:00"
},
{
"hour_selected":"13:00:00"
}
]
But i'm lost how can i do this with time hour ranges.
Any help greatly appricated.
PS: I'm creating array from mysql datetime field.
the simpliest solution is to use unix timestamp:
<?php
$timeFrom = '08:00:00';
$timeTo = '15:00:00';
function rangeBetweenHours($from, $to)
{
$timeFrom = strtotime('today ' . $from);
$timeTo = strtotime('today ' . $to);
$out = [];
foreach (range($timeFrom, $timeTo, 60 * 60) as $timestamp) { // 60 * 60 is a hour
$out[] = date('H:i:s', $timestamp);
}
return $out;
}
var_dump(rangeBetweenHours($timeFrom, $timeTo));
Here you can see working example:
http://sandbox.onlinephpfunctions.com/code/8fec4a2f6b067dc66705732b3c43301cc8722d3f
[
{
"order_id":"7",
"order_start_time":"08:00:00",
"order_end_time":"11:00:00",
"order_date":"29/03/2018"
},
{
"order_id":"8",
"order_start_time":"10:00:00",
"order_end_time":"01:00:00",
"order_date":"29/03/2018"
}
]
Apply for each on this and get order_start_time & order_end_time in an array then sort as per values associating as par increasing order of time.

Laravel - Model filter date field by month

I have a method that can receive a parameter of "month" and another of "year", you can receive both or only one of them.
In the case of only receiving the month I want to make a query that I look for in a field that is called "created_at" just looking for the month of that field date
At the moment I use this code but when doing a like it does not do it correctly
else if ($request->has('month')) {
$month = $request->input('month');
$currentTimestamp = date_create_from_format('n', $month)->getTimestamp();
$currentDate = date('m', $currentTimestamp);
$filters['updated_at'] = $currentDate;
unset($filters['month']);
}
$cars = Car::where(function($query) use($filters) {
foreach ($filters as $column => $value) {
if ($column === 'updated_at') {
$query->where($column, 'LIKE', '%'.$value.'%');
continue;
}
$query->where($column, 'LIKE', '%'.$value.'%');
}
})->orderBy('updated_at', 'desc')->get();
You should try this:
if ($request->has('month')) {
$month = $request->input('month');
Car::whereRaw('MONTH(created_at) = '.$month)->get();
}
You can use whereMonth method, like this:
$cars = Car::whereMonth('created_at', '12')->get();
Example with determining if a month value is exist:
if ($request->has('month')) {
$cars = Car::whereMonth('created_at', $request->input('month'))->get();
}
You can use laravel queryBuilder .
The idea is pretty simple. Build your query and execute it only when needed
carQuery = Car::newQuery();
if ($request->has('month') {
carQuery->where('created_at' .. do camparison you want);
}
if ( $request->has('year') {
// add extra query filter
}
cars = carQuery->get();

JSON Response Multidimensional Array

Hello i got a JSON response that looks like the one below. I want to count the posts that are younger then 24 hours and also check for unique user urls:
{
"meta":{
"network":"all",
"query_type":"realtime"
},
"posts":[
{
"network":"facebook",
"posted":"2014-08-16 08:31:31 +00000",
"sentiment":"neutral",
"url":"someURL",
"user":{
"name":"Terance Podolski",
"url":"someURL",
"image":"someURL"
}
},
{
"network":"facebook",
"posted":"2014-08-16 08:30:44 +00000",
"sentiment":"neutral",
"url":"someURL",
"user":{
"name":"Ɓukasz Podolski",
"url":"someURL",
"image":"someURL"
}
},
{
"network":"facebook",
"posted":"2014-08-16 08:25:39 +00000",
"sentiment":"neutral",
"url":"someURL",
"user":{
"name":"Marcin Podolski",
"url":"someURL",
"image":"someURL"
}
}
]
}
Thanks in advance.
With the help of #Elias Van Ootegem i got my problem solved. The code looks like that:
// Json Reponse decodieren
$jsonArray = json_decode($jsonData);
function getMentionsFromLast24H($myArray){
// set variable exactly one day ago
$since = new DateTime('-1 day');
// array where to store timestamps in
$recent = array();
foreach ( $myArray -> posts as $post ) {
try {
$post -> posted = new DateTime (substr ( $post->posted,0,19 ) );//create DateTime instance
if ( $post -> posted >= $since )
$recent[] = $post;//add to array
} catch ( Exception $e ) {
echo $e -> getMessage();
exit(1);
}
}
return $recent;
}
$mentions24h = count(getMentionsFromLast24H($jsonArray));
print_r($mentions24h);
It's pretty simple, really: decode the json data, compare the posted values with time - 24 hours, if the value is great than time-24 hours, add it to an array. That's it, you'll end up with an array containing all posts that were added in the last 24 hours:
$data = json_decode($jsonData);//creates object
$since = new DateTime('yesterday');
$recent = array();//this is the array we'll be constructing
foreach ($data->posts as $post)
{
$post->posted = new DateTime($post->posted);//create DateTime instance
if ($post->posted > $since)
$recent[] = $post;//add to array
}
var_dump($recent);//this is the array you're after
That really is all there is to it.

Categories