How to subtract time from time array using php? - php

Hello seniors I have a question related to some PHP script.
I have an array containing time => ['12:10', '4:16', '2:5'] and have one html form containing input field of type 'number'.
I want when I enter some value in my form input field for example I enter 7, so after submitting the form in back-end the number 7 which i enter in input field is subtracted from the array which I mentioned above and I will get the result array like:
['5:10', '4:16', '2:5']
I have tried something like that but not able to implement my logic
$val = array(1, 0, 2, 1, 1);
$subtract = 3.5;
foreach ($val as $key => $item) {
if ($subtract >= $item) {
$subtract -= $item;
$val[$key] = 0;
} else {
$val[$key] -= $subtract;
$subtract = 0;
}
}
Any kind of help is highly appreciated

You can use Carbon library for date/time manipulation:
<?php
use Carbon\Carbon;
$times = ['17:46', '03:05', '21:56'];
$timeshift = 3;
$new_times = array_map(
fn($t) => Carbon::createFromFormat('H:i', $t)
->subHours($timeshift)
->format('H:i'),
$times
);
Test Carbon library online

No need for library, just convert your first array to seconds: 1 hour = 3600 ; 1 minute = 60 ; 12:10 is 12 x 3600 + 10 x 60, then you do the same thing to your $_POST value, then use gmdate() to retrieve the original format of your array
$myTimes=array('12:10', '4:16', '2:5');
//do the math
$splittedTime = explode(":", $myTimes[0]); //in your case
$timeInSeconds = $splittedTime[0] * 3600 + $splittedTime[1] * 60 ;
//do the same thing to your your $_POST value if needed or simply
$totalReduceby = 7 * 3600;
// get new total of seconds
$newTime= $timeInSeconds - $totalReduceby;
$result = ltrim(gmdate("H:i", $newTime),0); //ltrim to remove the leading 0
$myTimes=array($result, '4:16', '2:5');
//print_r($myTimes);

time => ['12:10', '4:16', '2:5']
[...]
the number 7 which i enter in input field is subtracted from the array
I will get the result array like: ['5:10', '4:16', '2:5']
Your example is a little ambiguous. Do you only want to subtract the field value from the first element of the array, always? Or only from those elements which are greater than the submitted value?
It's pretty straightforward to subtract minutes from a mm:ss time string; simplest is probably to generalize so that the amount to subtract is also allowed to be mm:ss instead of always being a whole number of minutes. I would just explode both of them, turn them into total seconds (minutes*60+seconds), subtract those, and then turn back into mm:ss. Both conversions might be worth their own functions:
function mmssToSeconds($timeStr) {
if (str_contains($timeStr, ':')) {
list($min, $sec) = explode(':', $timeStr);
} else {
list($min, $sec) = array($timeStr, 0);
}
if ($min < 0) {
return 60*$min - $sec;
} else {
return 60*$min + $sec;
}
}
function secondsToMmss($seconds) {
$abs = abs($seconds);
$sgn = $seconds / $abs;
$min = floor($abs / 60);
$sec = $abs % 60;
return ($sgn < 0 ? '-' : '').sprintf('%d:%02d', $min, $sec);
}
And then the subtraction is easy:
function subtractMinutes($from, $delta) {
return secondsToMmss(mmssToSeconds($from) - mmssToSeconds($delta));
}
If you want to subtract from each element that is big enough, you could use a loop like this:
foreach ($ary['time'] as $i => $t) {
if ((int)$t > $subtract) {
$ary['time'][$i] = subtractMinutes($t, $subtract);
}
}
The comparison works because the cast from string to int ignores everything after the first non-digit, so '12:10' just becomes 12, which is > 7.

Related

compare driving distance from JSON array

I'm using googledistancematrix api for calculating distance from login user to all my fields of db. That's my controller code.
$field_list = Field::all();
for ($i=0; $i < count($field_list); $i++)
{
$destination = $field_list[$i]['latitude'] . "," . $field_list[$i]['longitude'];
$details = "http://maps.googleapis.com/maps/api/distancematrix/json?origins=$origin&destinations=$destination&mode=driving&sensor=false";
$json = file_get_contents($details);
$details = json_decode($json, TRUE);
if (count($details['destination_addresses']) > 0 )
{
$distance = $details['rows'][0]['elements'][0]['duration']['text'];
$field_list[$i]->distance = $distance;
}
}
By this i'm getting following response:
https://jsoneditoronline.org/?id=a35cedef327244ceb19ed35a2a4c8ddf
But i want to show only those fields whose distance < or = 30 mins.
Thanks
It's a simple matter to convert the time to seconds using strtotime() as follows:
$time=strtotime($details['rows'][0]['elements'][0]['duration']['text']);
if (($time-time()>1800) {
// ignore this element, probably in loop so do a continue
}
This is based on using your example line above which is only for a single element. You would need to wrap it with a loop and perform the calculation for each element.
You can use strtotime
$min = strtotime("30 mins");
$val = strtotime("0 hours 10 mins");
echo $min <= $val? "yes":"no";
(here if you want to test it)
in your case
if (count($details['destination_addresses']) > 0 ){
$min = strtotime("30 mins");
$distance = $details['rows'][0]['elements'][0]['duration']['text'];
if($min <= strtotime($distance)){
//do your logic
}
}

PHP - Generate random numbers with no duplicates

I'm building an advent calendar in PHP 7 and want to show dates 1 - 24 in a random order.
I've got a jquery plugin which can randomise my div elements, but it's not very good, and I want to know how to do it in PHP.
My code to output the dates looks (in simplified terms) like this:
for ($d = 1; $d <= 24; $d++) {
echo $d;
}
My plan was to instead use rand(1, 24) then store any numbers that had been generated in an array, e.g.
$date = rand(1, 24);
$used_dates[] = $date;
Then check $used_dates when picking a new date, e.g.
$unique_date = false;
while (!$unique_date) {
$date = rand(1, 24);
if (!in_array($date, $used_dates)) {
$used_dates[] = $date;
$unique_date = true;
}
}
This seems inefficient though. Are there better ways?
In your case, you need create range array of numbers, and then simply shuffle them
$days = range(1,24);
shuffle($days);
Thats all
You can use shuffle() method.
Shuffle() take an array and order rows randomly.
$array = array("a", "b", "c");
shuffle($array);
// OUTPUT is random
$numbers = range(1, 24);
shuffle($numbers);

Generate an array in PHP of random number not close to the X previous element

I want to generate in PHP an array of random numbers, but each number should not be the same as any of the X (for example 2 ) numbers bofore it and not even close to any of them by a define range (for example 5).
So for example:
I need numbers between 1 and 100
i've set my "range" to 5
the first two generated number are 20 and 50.
the third number will be a random number between 1 and 100, excluding all the numbers between 15 and 25, and between 45 and 55.
I can't figure out a function to achieve it. Ideally I want to call something like this:
getRandomNumbers( $min, $max, $previous, $range);
where $previous is the number of previous elements to take in consideration when generating the next one and $range is the "proximity" to those number where I don't want the next number to be.
I hope I explained in a decent way my request. :) Please, add a comment if you have any question about it.
I just came up with this:
function getRandomNumbers($min, $max, $previous, $range) {
static $generated = array();
$chunk = array_slice($generated, -$previous);
// Added this infinite loop check to save you some headache.
if (((($max - $min + 1) / (($range * 2) + 1)) + 1) <= $previous) {
die("Values set have the potential of running into an infinite loop. Min: $min, Max: $max, Previous: $previous, Range: $range");
}
while(true) {
$number = rand($min, $max);
$found = true;
foreach ($chunk as $value) {
if (in_array($number, range($value-$range, $value+$range))) {
$found = false;
}
}
if ($found) {
$generated[] = $number;
return $number;
}
}
}
Test it using this:
for ($i = 1; $i < 25; $i++) {
echo getRandomNumbers(1, 100, 5, 5) . "<br />";
}
PHPFiddle Link: http://phpfiddle.org/main/code/51ke-4qzs
Edit: Added a check to prevent a possible infinite loop. For example: if you set the following values:
$min = 1;
$max = 100;
$previous = 5;
$range = 12;
echo getRandomNumbers($min, $max, $previous, $range);
Then let's say, in a really unfortunate situation it would generate 13, 38, 63 and 88. So the 5th number cannot be anything between 1 and 25, 26 and 50, 51 and 75, 76 and 100. So it would result in an infinite loop. I've updated the PHPFiddle link as well.
getRandomNumbers( $previous, $range ) {
//I'm assuming that previous will be an array of your previous X that you don't want to be close to
$num = getRandomNumber() //However you are doing this now
foreach( $previous as $key => $value ) {
if ( ( $value - $range ) > $num && ( $value + $range ) < $num ) {
return getRandomNumbers($previous, $range);
}
}
//You need to also replace a value in previous
return num;
}

Using For loop inside function - not returning all values

I am having problems displaying the results of function calculateGrowth. As shown below, I would like to find the results for each day of a 10 day period. I used a for loop for obvious reasons. But when I try to display results, all I get back is one result.
function calculateGrowth(){
$days = 0;
$growth = 10;
for($days = 0; $days < 10; $days++){
$totalGrowth = $growth * pow(2, $days/10);
}
return $totalGrowth;
}
Current Output
18.6606598307
Desired Output
Day Growth
1 - result
. - result
. - result
10
$totalGrowth = $growth * pow(2, $days/10);
Should be
$totalGrowth[] = $growth * pow(2, $days/10);
^^
So that it becomes an array and contains all the values that you add to it, rather than being a string which gets overwritten on every iteration of the loop.
It sounds like what you're trying to get this:
function calculateGrowth() {
list($days, $growth, $table) = array(range(1, 10), 10, array());
foreach ($days as $day) {
$table[$day] = $growth * pow(2, $day/10);
}
return $table;
}
It is correct as your final loop is doing this
$totalGrowth = 10 * pow(2, 9/10)
$totalGrowth = 10*1.8660659830736;
$totalGrowth = 18.660659830736;
Edit : Removed last comment

Fill in absent elements in an array

I have a code that generates total posts from a database per hour for the latest 10 hours. Now, the problem is that only hours with posts are displayed, but that won't work for me because i want to display the whole thing as a chart.
Example of the current array:
array("12"=>"20403",
"15"=>"17017",
"17"=>"84013");
The keys represent the hour in a 24 format. So what i need is a function that fills in the empty hours with 0 value.
Example:
$currenthour=date('H'); // i think it may be based on the latest hour.
array("11"="0",
"12"=>"20403",
"13"=>"0",
"14"=>"0",
"15"=>"17017",
"16"=>"0",
"17"=>"84013",
"18"=>"0",
"19"=>"0",
"20"=>"0");
Thanks!
foreach(range(0, 23) as $hour)
if(!isset($ary[$hour]))
$ary[$hour] = 0;
ksort($ary);
to fill in only last hours you may need something like
function last_hours($hour, $cnt) {
return $hour < $cnt - 1 ?
array_merge(range($hour, 0), range(23, 25 - $cnt + $hour)) :
range($hour, $hour - $cnt + 1);
}
and then
$now = date("G");
$new_array = array();
foreach(last_hours($now, 10) as $hour)
$new_array[$hour] = isset($ary[$hour]) ? $ary[$hour] : 0;
Use array_fill OR do it with a loop (assuming $hours is your array:
$currenthour=date('H');
for($i = $currenthour; $i < 23; $i++)
if(!isset($hours[$i]))
$hours[$i] = 0;
You can simply iterate through the array, and see if the value at the index is set. Like this:
Edit with your the last 10 hours:
$currenthour=date('H')
$beginrange = $currenthour - 10
if ($beginrange =< 0)
$beginrange = 23 + $beginrange
$endrange = $currenthour
//set up the for loop
foreach(range($beginrange, $endrange) as $i)
//check if the element is set
if(!isset($array[$i]))
// set it
$array[$i] = 0;

Categories