I Have a log reading program written in PHP. I want to calculate the time difference of any given two log lines.
I found lot of code for calculating the time difference if the two times are give like
$time1='10:15:30'; and $time2='10:15:35';. here the time difference will be 5 seconds.
But here my input times will be as in the following format
$time1='10:15:30:300'; and $time2='11:15:35:450';
I want a function which will receive this times as inputs and give the time difference in milliseconds.
Is there any inbuilt php function that can be utilized for this purpose ? or should we write our custom logic to split this time and then calculate the difference ?
My suggestion would be to find the difference in seconds first between the 2 times ignoring the milliseconds part.
So say, you have
$time1='10:15:30:300';
$time2='11:15:35:450';
In this case you will see that the seconds difference = 3605 seconds.
Now calculate the milliseconds difference and maybe format it as 3605.150
If the milliseconds difference is negative, reduce the second by 1.
Two functions which may help you with your time related development and calculations are the following
function find_time_diff($t1, $t2) {
$a1 = explode(":", $t1);
$a2 = explode(":", $t2);
$time1 = (($a1[0] * 60 * 60) + ($a1[1] * 60) + ($a1[2]));
$time2 = (($a2[0] * 60 * 60) + ($a2[1] * 60) + ($a2[2]));
$diff = abs($time1 - $time2);
return $diff;
}
and my favorite... this can return in minutes, days,years and so on
function find_date_diff($start_date, $end_date, $formatreturn = 'minutes') {
list($date, $time) = explode(' ', $start_date);
if ($time == null) {
$time = '00:00:00';
}
if ($date == null) {
$date = date("Y-m-d");
}
$startdate = explode("-", $date);
$starttime = explode(":", $time);
list($date, $time) = explode(' ', $end_date);
if ($time == null) {
$time = '00:00:00';
}
if ($date == null) {
$date = date("Y-m-d");
}
$enddate = explode("-", $date);
$endtime = explode(":", $time);
$secons_dif = mktime($endtime[0], $endtime[1], $endtime[2], $enddate[1], $enddate[2], $enddate[0]) - mktime($starttime[0], $starttime[1], $starttime[2], $startdate[1], $startdate[2], $startdate[0]);
switch ($formatreturn) {
//In Seconds:
case 'seconds':
$choice = $secons_dif;
break;
//In Minutes:
case 'minutes':
$choice = floor($secons_dif / 60);
break;
//In Hours:
case 'hours':
$choice = floor($secons_dif / 60 / 60);
break;
//In days:
case 'days':
$choice = floor($secons_dif / 60 / 60 / 24);
break;
//In weeks:
case 'weeks':
$choice = floor($secons_dif / 60 / 60 / 24 / 7);
break;
//In Months:
case 'months':
$choice = floor($secons_dif / 60 / 60 / 24 / 7 / 4);
break;
//In years:
case 'years':
$choice = floor($secons_dif / 365 / 60 / 60 / 24);
break;
}
$choice;
return $choice;
}
Try this function:
function mtime_difference($t1, $t2) {
$t1 = DateTime::createFromFormat('H:i:s:u', $t1, new DateTimezone('UTC'));
$t2 = DateTime::createFromFormat('H:i:s:u', $t2, new DateTimezone('UTC'));
$diff = $t2->diff($t1);
$seconds = $diff->h * 3600 + $diff->i * 60 + $diff->s;
$u = $t1->format('u') - $t2->format('u');
if ($u < 0) {
$seconds--;
$u = 1000000 - abs($u);
}
$u = substr(sprintf('%06d', $u), 0, 3);
return $seconds . '.' . $u;
}
echo mtime_difference('11:15:35:450', '10:15:30:300');
# 3605.150
demo
#Glavic - small typo in your method, this line:
$u = $t1->format('u') - $t2->format('u');
should be:
$u = $t2->format('u') - $t1->format('u');
At first, your times are written wrong. There should be decimal dot before milliseconds.
It means there will be times
10:15:30.300 and 11:15:35.450
instead
10:15:30:300 and 11:15:35:450
But in class written below you could improve pattern to it would fit your time formatting. Or change whole checking.
For similar case I had to solve very recently (reading of csv files created by smartphone/tablet app IoTools and counting milliseconds differences between times), and based on question How to get time difference in milliseconds, I prepared class that does it - but only within range of one day (24 hours).
It is not perfect (as it could get some more options) but it computes well (I hope that it does well, I have not tested it much).
For this answer, I deleted details of exceptions throwing and rewrote some constants by their values. Also I deleted annotations to make code shorter, but replaced them with descripting texts.
class DayTimeCount
{
Times are converted into milliseconds. So, these two variables may be typed as integer.
protected $Time_Start = 0;
protected $Time_End = 0;
Also time scale may be as integer. Name of this variable may be a bit unfortunate, as it is not fully correctly saying for what purpose it is used.
protected $Time_Scale = 1;
This variable could be a constant. Its content is not changed at all.
private $TimePattern = '/(?<Hours>[0-9]{2})\:(?<Minutes>[0-9]{2})\:(?<Seconds>[0-9]{2}).(?<Milliseconds>[0-9]{0,3})/';
This function is for setting of start time (time when starts interval you need to count). After checking if time is set in correct pattern (as string corresponding pattern writen above, not integer), time is converted into milliseconds.
public function Set_StartTime($Time = NULL)
{
try
{
if( !preg_match($this -> TimePattern, $Time, $TimeUnits) )
{
throw new Exception(/* some code */);
}
}
catch( Exception $Exception )
{
$Exception -> ExceptionWarning(/* some code */);
}
$this -> Time_Start = ($TimeUnits['Hours'] * 60 * 60 * 1000) + ($TimeUnits['Minutes'] * 60 * 1000) + ($TimeUnits['Seconds'] * 1000) + $TimeUnits['Milliseconds'];
}
This function is similar to previous, but for setting of end time (time when ends interval you need to count).
public function Set_EndTime($Time = NULL)
{
try
{
if( !preg_match($this -> TimePattern, $Time) )
{
throw new Exception(/* some code */);
}
}
catch( Exception $Exception )
{
$Exception -> ExceptionWarning(/* some code */);
}
$this -> Time_End = ($TimeUnits['Hours'] * 60 * 60 * 1000) + ($TimeUnits['Minutes'] * 60 * 1000) + ($TimeUnits['Seconds'] * 1000) + $TimeUnits['Milliseconds'];
}
This function is for setting of time scale. It helps to convert milliseconds to seconds (with precision of milliseconds) or minutes or hours.
Static function Check_IsTimeScale is my own function that works as in_array().
public function Set_TimeScale($Scale = 1)
{
try
{
if( !Core::Check_IsTimeScale($Scale) )
{
throw new Exception(/* some code */);
}
}
catch( Exception $Exception )
{
$Exception -> ExceptionWarning(/* some code */);
}
$this -> Time_Scale = $Scale;
}
And finally, function is for own counting of time difference. It has only three steps.
public function Execute()
{
The first one is own counting. If difference between end and start is positive number (greater than zero), it is taken as it is.
But if difference between end and start is negative (as end is after midnight and start is before midnight, for example 00:00:00.658 and 23:59:59:354), then it is needed to use additional counting. To make difference between start and full time of day - and add end time.
$Diff = $this -> Time_End - $this -> Time_Start;
if( $Diff < 0 )
{
$Diff = $this -> Time_End + (86400000 - $this -> Time_Start);
}
The second step, application of time scale. Time in milliseconds is divided by time scale. If it is divided by 1, result is (of course) the same as original number and it is no rounded. If it is divided by larger number (1000 or greater from allowed options), it is rounded to length of number used to divide it.
$Diff = round($Diff / $this -> Time_Scale, strlen($this -> Time_Scale));
Third step is returning of final result. Probably it could be merged with previous step, but now it is (at least) better readable.
return $Diff;
}
}
Function ExceptionWarning is also my function, and can be replaced by your own one.
Related
I want to get round values of system time.
For example consider, now time is 6:02PM and I want to get the output as 6:05PM.
Is there any method???
You can use the ceil function with php:
$next_five = ceil(time()/300)*300;
this will give you the next round five minutes
$now = time();
$next_five = ceil($now/300)*300;
This will round up even if one second above a five minute mark
User below function
function blockMinutesRound($hour, $minutes = '5', $format = "H:i") {
$seconds = strtotime($hour);
$rounded = round($seconds / ($minutes * 60)) * ($minutes * 60);
return date($format, $rounded);
}
//call
blockMinutesRound('20:11');// return 20:10
Hope it helps ;)
I am trying to convert a decimal time into an actual time format with hours and minutes, ie: in xx:xx hours.
My query is:
select SUM(vt.vluchtdec) AS vluchttijddecimal
from tbl_vluchtgegevens vg
left join tbl_vluchttijd vt
on vg.vluchttijddec = vt.vluchttijdID
WHERE vg.vertrekdatum <=NOW();
And I am echoing
. $row['vluchttijddecimal'] .
I have also tried this, but this also still gives me my response in a decimal format:
$result = mysql_query("select SUM(vt.vluchtdec) AS vluchttijddecimal
from tbl_vluchtgegevens vg
left join tbl_vluchttijd vt
on vg.vluchttijddec = vt.vluchttijdID
WHERE vg.vertrekdatum <=NOW();");
while($row = mysql_fetch_array($result))
{
$dec = $row['vluchttijddecimal'];
function
convertTime($dec)
{
// start by converting to seconds
$seconds = $dec * 3600;
// we're given hours, so let's get those the easy way
$hours = floor($dec);
// since we've "calculated" hours, let's remove them from the seconds variable
$seconds -= $hours * 3600;
// calculate minutes left
$minutes = floor($seconds / 60);
// remove those from seconds as well
$seconds -= $minutes * 60;
// return the time formatted HH:MM:SS
return lz($hours).":".lz($minutes).":".lz($seconds);
}
// lz = leading zero
function lz($num)
{
return (strlen($num) < 2) ? "0{$num}" : $num;
}
echo "" .$dec."";
In MS Access I would do something like this:
CInt([vluchttijddecimal]) & ":" & Format([vluchttijddecimal]*60 Mod 60;"00")
But this does not work or I don't know how to do so in MySQL / php.
For anyone that is interested... This is how you would convert decimal time (Where 0.1 == 6 minutes) to hours and minutes (0.2333 == 14 minutes) in MYSQL alone. no PHP is needed. This also accounts for the need to round seconds to minutes.
SELECT CONCAT(FLOOR(timeInDec),':', LPAD(ROUND((timeInDec - FLOOR(timeInDec)) * 60) % 60,2,0)) AS TimeInHoursMinutes
FROM YourTable;
Replace timeInDec with the column name that contains the decimal time you would like to convert.
This will return 0:06 for 0.1000 decimal value so leading zeros are accounted for in single digit minutes.
You can do this in you SQL statement something like this:
SELECT CONCAT(CEIL(mydecimal),':', LPAD(Floor(mydecimal*60 % 60),2,'0')) as formated text
Where mydecimal is your unformatted field name
I think I have calculated your time values... although it was kinda pain.
It appears your "decimal time" is "hours.minutes"? Rather horrible and definitely not a good format: for dealing with time its best to stick to integers that specify either a total of minutes/seconds/hours or whatever granularity you need.
But assuming it is hours.minutes, you should be able to do it like this in PHP:
while($row = mysql_fetch_array($result))
{
$dec = $row['vluchttijddecimal'];
return sprintf("%2d:%2d", floor($dec), floor(($dec - floor($dec))*100));
}
Hopefully I am correct in assuming that you mean, for example that 2.5 hours = 2H 30mins. If so, then your 'time' is a time interval and is best represented by the DateInterval class.
This function will do what you want:-
/**
* Converts a 'decimal time' in the format 1.5hours to DateInterval object
*
* #param Int $decimalTime
* #return DateInterval
*/
function decTimeToInterval($decimalTime)
{
$hours = floor($decimalTime);
$decimalTime -= $hours;
$minutes = floor($decimalTime * 60);
$decimalTime -= ($minutes/60);
$seconds = floor($decimalTime * 3600);
$interval = new \DateInterval("PT{$hours}H{$minutes}M{$seconds}S");
return $interval;
}
echo decTimeToInterval(512.168)->format("%H:%I:%S");
See it working
If you want to add times in the format 'H:i' without converting them to and from decimals, you can do it like this:-
function sumTimes($time1, $time2)
{
list($hours1, $minutes1) = explode(':', $time1);
list($hours2, $minutes2) = explode(':', $time2);
$totalHours = $hours1 + $hours2;
$totalMinutes = $minutes1 + $minutes2;
if($totalMinutes >= 60){
$hoursInMins = floor($totalMinutes/60);
$totalHours += $hoursInMins;
$totalMinutes -= ($hoursInMins * 60);
}
return "$totalHours:$totalMinutes";
}
echo sumTimes('12:54', '100:06') . PHP_EOL;
echo sumTimes('12:54', '100:20') . PHP_EOL;
See it working
This is what I used for my Payroll System:
SELECT If(total_late>0, LPAD(CONCAT(REPLACE(FLOOR(total_late/60) + FORMAT(total_late%60*0.01,2), '.', ':'), ':00'), 8, 0), '00:00:00') FROM MyTable
I multiplied it by 0.01 because my variables are in Seconds. Eg. 60.00 = 1min
I would suggest this to include seconds. It is based on #Richard's solutions. Just notice I've changed CEIL by FLOOR in #Richard's solution.
SET #timeInDec=1.505;
SELECT CONCAT(FLOOR(#timeInDec),':', LPAD(FLOOR(#timeInDec*60 % 60),2,'0'),':', LPAD(FLOOR(MOD(#timeInDec*60 % 60,1)*100),2,0)) as timeInDec;
Ok so I am working on a calendar application within my CRM system and I need to find the upper and lower bounds of the half an hour surrorunding the timestamp at which somebody entered an event in the calendar in order to run some SQL on the DB to determine if they already have something booked in within that timeslot.
For example I have the timestamp of 1330518155 = 29 February 2012 16:22:35 GMT+4
so I need to get 1330516800 and 1330518600 which equal 16:00 and 16:30.
If anyone has any ideas or think I am approaching developing the calendar in a stupid way let me know! Its my first time on such a task involving so much work with times and dates so any advice appreciated!
Use modulo.
$prev = 1330518155 - (1330518155 % 1800);
$next = $prev + 1800;
The modulo operator gives the remainder part of division.
I didn't read the questions clearly, but this code will round to the nearest half hour, for those who don't need the range between the two. Uses some of SenorAmor's code. Props and his mad elegant solution to the correct question.
$time = 1330518155; //Or whatever your time is in unix timestamp
//Store how many seconds long our rounding interval is
//1800 equals one half hour
//Change this to whatever interval to round by
$INTERVAL_SECONDS = 1800; //30*60
//Find how far off the prior interval we are
$offset = ($time % $INTERVAL_SECONDS);
//Removing this offset takes us to the "round down" half hour
$rounded = $time - $offset;
//Now add the full interval if we should have rounded up
if($offset > ($INTERVAL_SECONDS/2)){
$nearestInterval = $rounded + $INTERVAL_SECONDS;
}
else{
$nearestInterval = $rounded
}
You could use the modulo operator.
$time -= $time % 3600; // nearest hour (always rounds down)
Hopefully this is enough to point you in the right direction, if not please add a comment and I'll try to craft a more specific example.
PHP does have a DateTime class and a whole slough of methods that it provides. You could use these if you like, but I find it easier to use the built-in date() and strtotime() functions.
Here's my solution:
// Assume $timestamp has the original timestamp, i.e. 2012-03-09 16:23:41
$day = date( 'Y-m-d', $timestamp ); // $day is now "2012-03-09"
$hour = (int)date( 'H', $timestamp ); // $hour is now (int)16
$minute = (int)date( 'i', $timestamp ); // $minute is now (int)23
if( $minute < 30 ){
$windowStart = strtotime( "$day $hour:00:00" );
$windowEnd = strtotime( "$day $hour:30:00" );
} else {
$windowStart = strtotime( "$day $hour:30:00" );
if( ++$hour > 23 ){
// if we crossed midnight, fix the date and set the hour to 00
$day = date( 'Y-m-d', $timestamp + (24*60*60) );
$hour = '00';
}
$windowEnd = strtotime( "$day $hour:00:00" );
}
// Now $windowStart and $windowEnd are the unix timestamps of your endpoints
There are a few improvements that can be made on this, but that's the basic core.
[Edit: corrected my variable names!]
[Edit: I've revisited this answer because, to my embarrassment, I realized that it didn't handle the last half-hour of a day correctly. I've fixed that issue. Note that $day is fixed by adding a day's worth of seconds to the timestamp -- doing it this way means we don't have to worry about crossing month boundaries, leap days, etc. because PHP will format it correctly for us regardless.]
If you need to get the current time and then apply the rounding (down) of the time, I would do the following:
$now = date('U');
$offset = ($now % 1800);
$now = $now-$offset;
for ($i = 0;$i < 24; $i++)
{
echo date('g:i',$now);
$now += 1800;
}
Or you could round up by adding the offset, and do something more than just echo the time. The for loop then displays the 12 hours of increments. I used the above in a recent project.
I'd use the localtime and the mktime function.
$localtime = localtime($time, true);
$localtime['tm_sec'] = 0;
$localtime['tm_min'] = 30;
$time = mktime($localtime);
Far from my best work... but here's some functions for working with string or unix time stamp.
/**
* Takes a timestamp like "2016-10-01 17:59:01" and returns "2016-10-01 18:00"
* Note: assumes timestamp is in UTC
*
* #param $timestampString - a valid string which will be converted to unix with time()
* #param int $mins - interval to round to (ex: 15, 30, 60);
* #param string $format - the format to return the timestamp default is Y-m-d H:i
* #return bool|string
*/
function roundTimeString( $timestampString, $mins = 30, $format="Y-m-d H:i") {
return gmdate( $format, roundTimeUnix( time($timestampString), $mins ));
}
/**
* Rounds the time to the nearest minute interval, example: 15 would round times to 0, 15, 30,45
* if $mins = 60, 1:00, 2:00
* #param $unixTimestamp
* #param int $mins
* #return mixed
*/
function roundTimeUnix( $unixTimestamp, $mins = 30 ) {
$roundSecs = $mins*60;
$offset = $unixTimestamp % $roundSecs;
$prev = $unixTimestamp - $offset;
if( $offset > $roundSecs/2 ) {
return $prev + $roundSecs;
}
return $prev;
}
This is a solution using DateTimeInterface and keeping timezone information etc. Will also handle timezones that are not a multiple of 30 minutes offset from GMT (e.g. Asia/Kathmandu).
/**
* Return a DateTimeInterface object that is rounded down to the nearest half hour.
* #param \DateTimeInterface $dateTime
* #return \DateTimeInterface
* #throws \UnexpectedValueException if the $dateTime object is an unknown type
*/
function roundToHalfHour(\DateTimeInterface $dateTime)
{
$hours = (int)$dateTime->format('H');
$minutes = $dateTime->format('i');
# Round down to the last half hour period
$minutes = $minutes >= 30 ? 30 : 0;
if ($dateTime instanceof \DateTimeImmutable) {
return $dateTime->setTime($hours, $minutes);
} elseif ($dateTime instanceof \DateTime) {
// Don't change the object that was passed in, but return a new object
$dateTime = clone $dateTime;
$dateTime->setTime($hours, $minutes);
return $dateTime;
}
throw new UnexpectedValueException('Unexpected DateTimeInterface object');
}
You'll need to have created the DateTime object first though - perhaps with something like $dateTime = new DateTimeImmutable('#' . $timestamp). You can also set the timezone in the constructor.
Math.round(timestamp/1800)*1800
As you probably know, a UNIX timestamp is a number of seconds, so substract/add 1800 (number of seconds in 30 minutes) and you will get the desired result.
Here's a more semantic method for those that have to make a few of these, perhaps at certain times of the day.
$time = strtotime(date('Y-m-d H:00:00'));
You can change that H to any 0-23 number, so you can round to that hour of that day.
I am trying to take a decimal and convert it so that I can echo it as hours, minutes, and seconds.
I have the hours and minutes, but am breaking my brain trying to find the seconds. Been googling for awhile with no luck. I'm sure it is quite simple, but nothing I have tried has worked. Any advice is appreciated!
Here is what I have:
function convertTime($dec)
{
$hour = floor($dec);
$min = round(60*($dec - $hour));
}
Like I said, I get the hour and minute without issue. Just struggling to get seconds for some reason.
Thanks!
If $dec is in hours ($dec since the asker specifically mentioned a decimal):
function convertTime($dec)
{
// start by converting to seconds
$seconds = ($dec * 3600);
// we're given hours, so let's get those the easy way
$hours = floor($dec);
// since we've "calculated" hours, let's remove them from the seconds variable
$seconds -= $hours * 3600;
// calculate minutes left
$minutes = floor($seconds / 60);
// remove those from seconds as well
$seconds -= $minutes * 60;
// return the time formatted HH:MM:SS
return lz($hours).":".lz($minutes).":".lz($seconds);
}
// lz = leading zero
function lz($num)
{
return (strlen($num) < 2) ? "0{$num}" : $num;
}
Very simple solution in one line:
echo gmdate('H:i:s', floor(5.67891234 * 3600));
Everything upvoted didnt work in my case.
I have used that solution to convert decimal hours and minutes to normal time format.
i.e.
function clockalize($in){
$h = intval($in);
$m = round((((($in - $h) / 100.0) * 60.0) * 100), 0);
if ($m == 60)
{
$h++;
$m = 0;
}
$retval = sprintf("%02d:%02d", $h, $m);
return $retval;
}
clockalize("17.5"); // 17:30
I am not sure if this is the best way to do this, but
$variabletocutcomputation = 60 * ($dec - $hour);
$min = round($variabletocutcomputation);
$sec = round((60*($variabletocutcomputation - $min)));
This is a great way and avoids problems with floating point precision:
function convertTime($h) {
return [floor($h), (floor($h * 60) % 60), floor($h * 3600) % 60];
}
I need to find how much time is between to time values (their difference) which are over 24:00:00.
For example: how can I calculate the difference between 42:00:00 and 37:30:00?
Using strtotime, strptotime, etc is useless since they cannot go over 23:59:59 ....
$a_split = explode(":", "42:00:00");
$b_split = explode(":", "37:30:00");
$a_stamp = mktime($a_split[0], $a_split[1], $a_split[2]);
$b_stamp = mktime($b_split[0], $b_split[1], $b_split[2]);
if($a_stamp > $b_stamp)
{
$diff = $a_stamp - $b_stamp;
}else{
$diff = $b_stamp - $a_stamp;
}
echo "difference in time (seconds): " . $diff;
then use date() to convert seconds to HH:MM:SS if you want.
Date/Time variables and functions are not appropriate here as you're not storing time, but instead a time span of (I assume) hours, minutes, and seconds.
Likely your best solution is going to be to split each time span into their integer components, convert to a single unit (for instance, seconds), subtract them from each other, then re-build an output time span that fits with your application.
I havent tested this, but this might do what you want:
function timediff($time1, $time2) {
list($h,$m,$s) = explode(":",$time1);
$t1 = $h * 3600 + $m * 60 + $s;
list($h2,$m2,$s2) = explode(":",$time2);
$seconds = ($h2 * 3600 + $m2 * 60 + $s2) - $t1;
return sprintf("%02d:%02d:%02d",floor($seconds/3600),floor($seconds/60)%60,$seconds % 60);
}