In this website I've found a function to convert seconds in an human readable format, like this:
3 weeks, 2 days, 1 hour, 27 minutes, 52 seconds
I want to translate it in italian, so I just translated array keys. The function now is this
function secondsToHumanReadable($secs) {
$units = array(
'settimane' => 604800,
'giorni' => 86400,
'ore' => 3600,
'minuti' => 60,
'secondi' => 1
);
foreach ( $units as &$unit ) {
$quot = intval($secs / $unit);
$secs -= $quot * $unit;
$unit = $quot;
}
return $units;
}
It works pretty well, but there's a little problem: in english all the plurals ends with one letter less, but unfortunately in italian it's not the same, as you can see below.
English Italian
- weeks, week - settimane, settimana
- days, day - giorni, giorno
- hours, hour - ore, ora
- minutes, minute - minuti, minuto
- seconds, second - secondi, secondo
I want to find a solution to print singular keys when the values are == 1.
I was thinking that I could merge the array with another array that have singular keys, using array_combine().
$singular_units = array(
'settimana',
'giorno',
'ora',
'minuto',
'secondo'
);
print_r(array_combine( $singular_units, $units ));
/* print_r:
Array
(
[settimana] => 604800
[giorno] => 86400
[ora] => 3600
[minuto] => 60
[secondo] => 1
)
*/
The array above is what I need, but I'm not able to use it, since I just cannot use another foreach.
$seconds = 12345*60; // just an example
$units = secondsToHumanReadable($seconds);
$time_string = '';
foreach ($units as $u => $v)
if (!empty($v))
$time_string.= $v.' '.$u.', ';
echo substr($time_string, 0, -2);
// 1 settimane, 1 giorni, 13 ore, 45 minuti
// this echo is not correct :( is expected to be like this:
// 1 settimana, 1 giorno, 13 ore, 45 minuti
How could I implement the singular words?
Any help is really appreciated! Thank you so much in advance!
You can implement them any way you like, IMHO preferably something not like the current solution which lacks clarity and readability (at least that's how the local-var-mutation-with-refs-and-variable-ping-pong looks like to me).
Just one possible solution:
$input = 12345 * 60;
$units = array(
604800 => array('settimana', 'settimane'),
86400 => array('giorno', 'giorni'),
// etc
);
$result = array();
foreach($units as $divisor => $unitName) {
$units = intval($input / $divisor);
if ($units) {
$input %= $divisor;
$name = $units == 1 ? $unitName[0] : $unitName[1];
$result[] = "$units $name";
}
}
echo implode(', ', $result);
See it in action.
Your probably want something like this?
function secondsToHumanReadable($secs) {
$units = array(
'settimane' => 604800,
'giorni' => 86400,
'ore' => 3600,
'minuti' => 60,
'secondi' => 1
);
foreach ( $units as $key => &$unit ) {
$this_unit = intval($secs / $unit);
$secs -= $this_unit * $unit;
if($this_unit == 1):
switch($key):
case "settimane":
$this_key = "settimana";
break;
case "giorni":
$this_key = "giorno";
break;
case "ore":
$this_key = "ora";
break;
case "minuti":
$this_key = "minuto";
break;
case "secondi":
$this_key = "secondo";
break;
endswitch;
else:
$this_key = $key;
endif;
$results[$this_key] = $this_unit;
}
return $results;
}
This will return the full array, not your initial one...with results...
Was also going to mention that some frameworks have Inflector classes which will determine the plural/singular version of a word, however I am not sure if they support languages such as Italian, but it may be worth a look. Personally I use CakePHP Inflector as it is a stand alone lib and I didn't need to bring in any other files.
CakePHP Inflector class
http://api.cakephp.org/class/inflector
Doctrine Inflector: http://www.doctrine-project.org/api/common/2.0/doctrine/common/util/inflector.html
Related
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.
In text, i have a lot of time number, then i want to change hour to another timezone (+6), example :
00:15 => 06:15
01:00 => 07:00
... and so on.
I'm trying this :
$result = str_replace(
array("00:","01:","02:","03:","04:","05:","06:","07:","08:","09:","10:","11:","12:","13:","14:","15:","16:","17:","18:","19:","20:","21:","22:","23:"),
array("06:","07:","08:","09:","10:","11:","12:","13:","14:","15:","16:","17:","18:","19:","20:","21:","22:","23:","00:","01:","02:","03:","04:", "05:"),
$text
);
echo $result;
But 18: will replace with 04: because php replace 18: to 22: then continue replace 22: to 04:
How to solved this, thank you.
// Edit : To #user3414969 and #Medda86: $text is the data i'm get from another site, that mean i can not control the source, only way to do is replace
// Edit 2 : Here is content : http://bongdatv.net/test.php
// Edit 3: Please solve this problem with replace way, not calculation number way.
I think best is to use the timestamp format, add the time and get out the new time from that.
http://php.net/manual/en/function.time.php
$time = array("00:","01:","02:","03:","04:","05:","06:","07:","08:","09:","10:","11:","12:","13:","14:","15:","16:","17:","18:","19:","20:","21:","22:","23:");
$required_time = array();
foreach($time as $t){
$hour = $t."00"; // 00 appending 0 minites
$hours_plus = 6; // adding 6 hours
$required_time[] = date('H:', strtotime($hour)+($hours_plus*60*60));
}
echo "<pre>";
print_r($required_time);
echo "</pre>";
Optimal way is as suggested by Medda86
However, you can try upon this way
$array = ("00:","01:",....);
//Then you can loop over array and add the time
for($i=0 ; $i < sizeof($array);$i++){
$array[$i] = intval($array[$i]+6)%24;
if($array[$i] < 10)
$array[$i] = str_pad($array[$i],2,'0',STR_PAD_LEFT).':';
else
$array[$i] .= ':';
}
Try this:
$yourArr = array('00:15','01:00','00:30');
foreach ($yourArr as $key => $value) {
$timestamp = strtotime($value) + 60*60*6; // add hours as per your need.
$time = date('H:i', $timestamp);
$newArr[] = $time;
}
echo "<pre>";
print_r($newArr);
Result is:
Array
(
[0] => 06:15
[1] => 07:00
[2] => 06:30
)
Given a birthdate in the form mm/dd/yyyy, write a function that returns the person's age and true or false if today is the person's birthday.
For example, since today is 01/23/2015, your function would return the following:
getBirthDate('02/26/1975'); // returns array('age' => 39, 'birthday' => false);
getBirthDate('01/23/1994'); // returns array('age' => 21, 'birthday' => true);
This is what I have and I just cant seem to find out why the output wont come out like I need it to. When I run this code, no output is shown, but I can't figure out what I did wrong. What I want it to do is when it is run, it should output the age and true or false if that date is the person's birthday. But whenever I run this piece of code, the output is always blank or it just says Array. I would appreciate any help or suggestions to solving this! Thanks!
<?php
function getBirthDate($birthdate)
{
$agebirthday = array();
list($D, $M, $Y) = explode("/", $birthdate);
$YearDifference = date("y") - $Y;
if (date("m") == $M && (date("d") == $D))
{
$Birthday = true;
}
else {
$Birthday = false;
}
array_push($agebirthday, array(
"age" => $YearDifference,
"birthday" => $Birthday));
return $agebirthday;
}
$output = getBirthDate($birthdate);
echo $output['age'];
echo $output['birthday'];
?>
Here's my version, I've changed a few things:
function getBirthDate($birthdate)
{
list($D, $M, $Y) = explode('/', $birthdate);
$YDiff = date('Y') - $Y;
// the line below is optional, you may wish to count complete years age or not
if(date("md") < $M.$D) $YDiff --; // if it's BEFORE birthday
return [
"age" => $YDiff,
"birthday" => date('md') == $M.$D
];
}
$output = getBirthDate('28/05/1981');
var_dump($output['age']);
var_dump($output['birthday']);
Gives us the correct answer, for my birthday:
int(33)
bool(false)
Make use of the strtotime() function. It converts dates to a large integer representing the number of seconds elapsed between the year 1970 and the date you specify, then subtract the value from the value of the time() function to get the number of seconds of time difference. Then use division on the result to get the desired number.
For example:
$seconds_old=time()-strtotime("02/26/1975");
Then you can do this:
$minutes_old=$seconds_old / 60;
$hours_old=$minutes_old / 60;
$days_old=$hours_old / 24;
$years_old=$days_old / 365;
And if the precision is too high, then research the intval() function.
in your code , change
array_push($agenbirthday, array(
"age" => $YDiff,
"birthday" => $Birthday));
to
$agenbirthday = array(
"age" => $YDiff,
"birthday" => $Birthday);
I need to implement this function into my website but however my language requires a bit more modification since it's not as it is in English adding only /s for plural. So, here it is:
Plural form:
години
месеци
седмици
дни
часа
минути
секунди
Non plural form:
година
месец
седмица
ден
час
минута
секунда
So, how I can make that change on the humanTiming function below?
$time = strtotime('2014-09-22 00:00:00');
echo 'Сървъра стартира преди '.humanTiming($time).'';
function humanTiming ($time)
{
$time = time() - $time; // to get the time since that moment
// Non plural forms
$tokens = array (
31536000 => 'година',
2592000 => 'месец',
604800 => 'седмица',
86400 => 'ден',
3600 => 'час',
60 => 'минута',
1 => 'секунда'
);
foreach ($tokens as $unit => $text) {
if ($time < $unit) continue;
$numberOfUnits = floor($time / $unit);
return $numberOfUnits.' '.$text.(($numberOfUnits>1)?'s':'');
}
}
Put in the token variable arrays of values, like this:
...
31536000 => array('година', 'години'), // singular, plural1, plural2?...
...
In the for loop select the appropriate value based on your number:
$text = $numberOfUnits > 1 ? $text[1] : $text[0];
return $numberOfUnits . ' ' . $text;
If you're making use of some sort of gettext implementation, it most likely comes with a function that handles these kind of things. For example, the gettext PHP extension has ngettext()
I'm trying to get the average time a user spends on my site using my own built analytics.
I'm using the DateTime class right now but the math seems very sketchy. Say I have an array of login times and logout times.
$array = array(
array("login" => '2012-01-31 10:35:58', "logout" => '2012-02-01 10:35:58'),
array("login" => '2012-02-04 10:35:58', "logout" => '2012-02-05 10:35:58')
);
I want to get the of amount of time between each login and logout, then find the average of all those times.
$total = 0;
$count = 0;
foreach ($array as $timestamp) {
$diff = strtotime($timestamp['logout']) - strtotime($timestamp['login']);
$total += $diff;
$count++;
}
echo "Average session time is ", $total / $count;
For safety's sake, you'd be better off using DateTime::createFromFormat() to do the date->time parsing. Your timestamps are a nice normal format, but strtotime is unreliable when you've got some wonky formats.
As well, this code assumes that all login/logout pairs are fully defined. If you have any where either time is off, you'll end up with some huge outliers as those'll most likely come out as 0, rather than a normal "modern" timestamp.
You could do something like:
$sessions = array();
foreach($array as $s) {
$sessions[] = strtotime($s['logout']) - strtotime($s['login']);
}
Now $sessions is an array of all the session lengths in seconds, so if you then do:
$average = array_sum($sessions) / count($sessions);
That is the average session length, in seconds. You could then print that in human-readable format, but I think that's beyond the scope of this question.
The reason I am putting the session lengths in an array first instead of simply summing them up in the loop is that you can then also get other statistics out of it, like longest/shortest sessions, median, etc.
Example using DateTime (tested).
define('DATETIME_FORMAT', 'Y-m-d H:i:s');
$array = array(
array('login' => '2012-01-31 10:35:58', 'logout' => '2012-02-01 10:35:58'),
array('login' => '2012-02-04 10:35:58', 'logout' => '2012-02-06 10:22:58')
);
$total = 0;
$count = 0;
foreach($array as $timeInfo)
{
$loginDatetime = DateTime::createFromFormat(DATETIME_FORMAT, $timeInfo['login']);
$logoutDatetime = DateTime::createFromFormat(DATETIME_FORMAT, $timeInfo['logout']);
$total += ($logoutDatetime->getTimestamp() - $loginDatetime->getTimestamp());
$count++;
}
$average = $total / $count;
echo "Average session duration: ".$average." seconds";
EDIT: initally I've used an array to store diffs, ending with array_sum() / count() to compute the average, but I found Marc B's solution with $total and $count simpler and certainly faster (it may matter here since potentially a lot of login/logout datetimes will be processed). => applied it here.
$array = array( array ("login" => "2012-01-31 10:35:58", "logout" => "2012-02-01 10:35:58"),
array ("login" => "2012-02-04 10:35:58", "logout" => "2012-02-05 10:35:58") );
$amount = 0 ;
foreach( $array as $at )
{
$amount += strtotime( $at[ "logout" ] ) - strtotime( $at[ "login" ] ) ;
}
$average = $amount / count( $array ) ;
echo "amount: $amount seconds\naverage $average seconds\n" ;