PHP: Calculate Real Differences Between Two Dates or Timestamps
I was using simple function to calculate difference between two dates and timestamps until I noticed, it’s not working correctly in long intervals. It’s very easy to calculate difference between two timestamps in seconds, but it’s much more complicated print difference in human readable format. The Internet can be found in a wide range of ways to do this thing, but as a rule they use a fixed amount of seconds for the year and the month. So if we calculate year with using 365 or 365.25 days and month using 30 or 31 then the difference is not accurate, because of leap years, DST (Daylight Saving Time) and so on.
Because of this problem, I decided to make a function (at least in the short testing) to return the right kind of differences between the UNIX timestamps and dates in human readable format. This function uses PHP strtotime function to calculate real differences and can handle leap years and DST. This function can also return Twitter like about texts with precision parameter.
PHP dateDiff function for calculating real differences between dates and UNIX timestamps
<?php // Set timezone date_default_timezone_set("UTC"); // Time format is UNIX timestamp or // PHP strtotime compatible strings function dateDiff($time1, $time2, $precision = 6) { // If not numeric then convert texts to unix timestamps if (!is_int($time1)) { $time1 = strtotime($time1); } if (!is_int($time2)) { $time2 = strtotime($time2); } // If time1 is bigger than time2 // Then swap time1 and time2 if ($time1 > $time2) { $ttime = $time1; $time1 = $time2; $time2 = $ttime; } // Set up intervals and diffs arrays $intervals = array('year','month','day','hour','minute','second'); $diffs = array(); // Loop thru all intervals foreach ($intervals as $interval) { // Set default diff to 0 $diffs[$interval] = 0; // Create temp time from time1 and interval $ttime = strtotime("+1 " . $interval, $time1); // Loop until temp time is smaller than time2 while ($time2 >= $ttime) { $time1 = $ttime; $diffs[$interval]++; // Create new temp time from time1 and interval $ttime = strtotime("+1 " . $interval, $time1); } } $count = 0; $times = array(); // Loop thru all diffs foreach ($diffs as $interval => $value) { // Break if we have needed precission if ($count >= $precision) { break; } // Add value and interval // if value is bigger than 0 if ($value > 0) { // Add s if value is not 1 if ($value != 1) { $interval .= "s"; } // Add value and interval to times array $times[] = $value . " " . $interval; $count++; } } // Return string with times return implode(", ", $times); } ?> |
dateDiff function example usage
strtotime examples:
echo dateDiff("2010-01-26", "2004-01-26") . "\n"; echo dateDiff("2006-04-12 12:30:00", "1987-04-12 12:30:01") . "\n"; echo dateDiff("now", "now +2 months") . "\n"; echo dateDiff("now", "now -6 year -2 months -10 days") . "\n"; echo dateDiff("2009-01-26", "2004-01-26 15:38:11") . "\n"; |
Output:
6 years 18 years, 11 months, 30 days, 23 hours, 59 minutes, 59 seconds 2 months 6 years, 2 months, 10 days 4 years, 11 months, 30 days, 8 hours, 21 minutes, 49 seconds
UNIX timestamp and precision examples
echo dateDiff(time(), time()-1000000, 1) . "\n"; echo dateDiff(time(), time()-1000000, 3) . "\n"; echo dateDiff(time(), time()-1000000, 6) . "\n"; |
Output:
11 days 11 days, 13 hours, 46 minutes 11 days, 13 hours, 46 minutes, 40 seconds
Converting text format back to UNIX timestamp example
$time1 = time(); $time2 = $time1-10000000; echo $diff = dateDiff($time1, $time2) . "\n"; echo $time1 . "\n"; echo strtotime(" +".$diff, $time2) . "\n"; |
Output:
3 months, 23 days, 17 hours, 46 minutes, 40 seconds 1264514564 1264514564
I was using simple function to calculate difference between two dates and timestamps until I noticed, it’s not working correctly in long intervals. It’s very easy to calculate difference between two timestamps in seconds, but it’s much more complicated print difference in human readable format. The Internet can be found in a wide range of ways to do this thing, but as a rule they use a fixed amount of seconds for the year and the month. So if we calculate year with using 365 or 365.25 days and month using 30 or 31 then the difference is not accurate, because of leap years, DST (Daylight Saving Time) and so on.
Hey JR, been a while since I’ve posted here… any way, I was wondering if you could help me with something. Below is the code used on my site and I was wondering if you could tell me what needs to be altered to number_format() the days so come the 3rd yr you wouldn’t see 1095 but instead would see 1,095.
Thx JR !
// Time format is UNIX timestamp or// PHP strtotime compatible strings
function dateDiff($time1, $time2, $precision = 4) {
// If not numeric then convert texts to unix timestamps
if (!is_int($time1)) {
$time1 = strtotime($time1);
}
if (!is_int($time2)) {
$time2 = strtotime($time2);
}
// If time1 is bigger than time2
// Then swap time1 and time2
if ($time1 > $time2) {
$ttime = $time1;
$time1 = $time2;
$time2 = $ttime;
}
// Set up intervals and diffs arrays
$intervals = array('Year', 'Day', 'Hour', 'Minute');
$interval_names = array('Year' => 'Yr', 'Day' => 'Day', 'Hour' => 'Hr', 'Minute' => 'Min');
$diffs = array();
// Loop thru all intervals
foreach ($intervals as $interval) {
// Set default diff to 0
$diffs[$interval] = 0;
// Create temp time from time1 and interval
$ttime = strtotime("+1" . $interval, $time1);
// Loop until temp time is smaller than time2
while ($time2 >= $ttime) {
$time1 = $ttime;
$diffs[$interval]++;
// Create new temp time from time1 and interval
$ttime = strtotime("+1" . $interval, $time1);
}
}
$count = 0;
$times = array();
// Loop thru all diffs
foreach ($diffs as $interval => $value) {
// Break if we have needed precission
if ($count >= $precision) {
break;
}
// Add value and interval
// if value is bigger than 0
if ($value > 0) {
// Add if value is not 1
if ($value != 1) {
$interval = $interval_names[$interval] . "s";
}
else {
$interval = $interval_names[$interval];
}
// Add value and interval to times array
$times[] = $value . " " . $interval;
$count++;
}
}
// Return string with times
return implode(", ", $times);
}
// echo dateDiff(1267074000, time(), 4) . "\n";
function addOrdinalSuffix($number) {
if (in_array(($number % 100),array(11,12,13))){
return $number.'th';
}
else {
switch (($number % 10)) {
case 1:
return $number.'st';
break;
case 2:
return $number.'nd';
break;
case 3:
return $number.'rd';
break;
default:
return $number.'th';
break;
}
}
}
$birthday_date = '2010-02-25';
$current_date = date('Y-m-d');
list($birthday_year, $birthday_month, $birthday_day) = explode("-", $birthday_date);
list($current_year, $current_month, $current_day) = explode("-", $current_date);
if ($birthday_month == $current_month && $birthday_day == $current_day) {
echo 'Happy ', addOrdinalSuffix($current_year - $birthday_year), ' B-Day myu2sig.com !';
echo "\n";
}
else {echo dateDiff(1267074000, time(), 4) . "\n";}
Hi again Andy :)
I don’t fully understand that what you want to do because I can’t find number_format() function in your code.
Could you please try to explain a bit more detailed, so I can try to help you…
number_format() is not in the code, what I am saying is that I want to make the days figured be encased by it.
So come the 3rd yr you wouldn’t see 1095 but instead would see 1,095.
As the code stands in it’s current format, shold 3 yrs go by you would see 1095 and thats just ugly to me.
Now do you get it ?
Hi Andy,
Try following:
That did it, thx.
Excellent! :D
@itsgreen – Anything prior to 1970/71 needs to be formatted like a negative number.
ex. -2204201921
That should allow this “script” to function with any date prior to 1970/71.
@itsgreen – Not sure if how you would do it but you could possibly code the “script” to add the – to the beginning of any timestamps that are prior to 1970 since in your case it sounds like your full on auto and not doing anything on a case by case basis.
@itsgreen and @andy
This function is designed to work only with UNIX timestamps, it’s reason why this is not working with anything prior 1970.
What is the UNIX time stamp?
The UNIX time stamp is a way to track time as a running total of seconds. This count starts at the Unix Epoch on January 1st, 1970. Therefore, the unix time stamp is merely the number of seconds between a particular date and the Unix Epoch. This is very useful to computer systems for tracking and sorting dated information in dynamic and distributed applications both online and client side.
@JR – In regards to my comments to itsgreen, your script does accurately work with dates / timestamps prior to 1970. I tested this with something from the 1900′s and it worked great. You just need the – at the beginning of the timestamps to say ok, this is before 1970.
This is what I used to get a timestamp from the 1900′s which I then plugged in to your system and it worked out just fine.
Epoch & Unix Timestamp Conversion Tools
very nice read and function works like charm, thank you
Thx for this script. I am using it to show how soon an event is coming up, but when it passes it should show “Overdue”. Any ideas?
I figured it out:
// if same day
if ($time1 == $time2) {
echo “TODAY”;
}
// if past
if ($time1 $time2) {
$ttime = $time1;
$time1 = $time2;
$time2 = $ttime;
}
// if same day
if ($time1 == $time2) { echo “TODAY”; }
// if past
if ($time1 $time2) {
$ttime = $time1;
$time1 = $time2;
$time2 = $ttime;
}
Hello
I as well like your dateDiff function thank you for sharing this function
I am using your above function on a timesheet db application where I calculate the total of the time worked ( time IN 7:00 AM time Out 5: 00 PM )
your function displays the time diff as expectected when displaying one timesheet or the time of single timesheets.
I display the last two weeks timesheets and I would need the total sum of worked time displayed. I wonder if I can modify your function maybe with a staic value
…
function dateDiff($time1, $time2, $precision = 6) {
static $SumTotalTime;
…
$times[] = $value . ” ” . $interval;
$SumTotalTime = ($SumTotalTime + $value);
$count++;
…
can someone please point me in the right direction how I could display the total time processed with the function from the page
thank you
Hi Vincent,
Glad to hear that you like dateDiff function.
In your case, is certainly an easier way to calculate the time between the two timestamp. I wrote quick class for you. If I understand correctly, what you’re doing, so the following example might work.
TimestampCalc class
Example usage
Output:
Dear Jr
Your class works but i think you maybe miss understood my goal
when displaying one time sheet your function and now your class works as expected ..
MY DB Tbl. TimeIN 08:00AM TimeOut: 05:00PM
I would display under the time sheet that the employee worked 9 hrs
But I as well would like to display the total hours and min worked when multiple timesheets are selected .. .
let me show you some code :
…
while($get_employee_sheet_data = mysql_fetch_array($check_employee_timeSheets)) {
$EmplSheetID = $get_employee_sheet_data['TimeSheetID'];
$EmplSheetDate =$get_employee_sheet_data['TimeSheetDate'];
$EmplSheetJobID = $get_employee_sheet_data['TimeSheetJobTitleID'];
$EmplSheetJobTitle = $get_employee_sheet_data['TimeSheetJobTitle'];
$EmplSheetIn = $get_employee_sheet_data['TimeSheetTimeIn'];
$EmplSheetOut = $get_employee_sheet_data['TimeSheetTimeOut'];
$tc = new TimestampCalc();
$tc->addTimeDiff($EmplSheetIn, $EmplSheetOut);
echo ““. $EmplSheetDate .” “. $EmplSheetJobTitle .” (“. $tc->getFormattedTotal() .”)
….
the above recordset shows the time worked of one record, just now I would need the total times calculated by your function so I have a total of the selected recordset exsample 10 timesheets etc.
thank you for your input and smarts
Hi again Vincent,
Actually, I understood what you wanted to do, but only partially. :) Example works for collecting total time and returns it as formatted, but can’t return every added time as formatted. So let’s try again:
New version of TimestampCalc class
Example usage
Output
Usage on your code
Jr thank you for your time and the way of writing the above class, It works well here for my timesheet application.
If you dont mind I would like to keep in touch with you.
Thank you again
I have to ask you another question what is in regarding the time difference
I am saving the above times as a varchar in the timesheet table ( 07:00 AM )
I had this issue that the date type is not so practicly in my timesheet application
it works very well now to calculate the times of the timesheet tx to your class ..
However Jr bevore entering new timesheet data into the table I have to check if the times are overlapping with already a saved timesheet. I wonder if you would again direct me in the right direction, i know if the times are saved as date time field i would have a query similar to seee below:
how would you write the timesheet overlap check because my fields are strings
Timesheet Add
…
}else{
$strSql=”SELECT * FROM `TimesheetTbl` WHERE `TimeSheetTimeIN` between ‘$strSheetTimeIN’ AND ‘$strSheetTimeOut’ OR `TimeSheetTimeOut`
between ‘$strSheetTimeIN’ AND ‘$strSheetTimeOut’ AND `TimeSheetDate` = ‘$strTimeSheetDate’ AND `TimeSheetUserID` = $EmpldbID”;
$check_time_sheet = mysql_query($strSql);
echo $strSql;
if(mysql_num_rows($check_time_sheet) != 0){
$final_report.=”found a recorded timesheet with overlapping times!”;
}else{
….
I wonder should I query first the existing times and format them or is it possible to check the overlapp via sql
Jr
I been searching online and testing so much with no success to check the times stored as string in the db for overlapping times . I as well asked in other forums and they say its not possible . I still dont think so . there must be a way of converting the string times on the fly in the sql or maybe in an array when I retrieve the existing times from a recordset.
Jr. If you think its not possible i change the db field type to a date field but it would be so much better if I can leave them as varchar and still validate the input
thanks for your input
Hi again Vincent,
Nice to hear that my class work on your timesheet application. :)
I’ve been a little busy, but here’s my thoughts to the problem.
First, the best way to store the date and time is of course the database fields that are real date and time types.
But I think that your situation is not impossible. You could use MySQL STR_TO_DATE function to convert your varchar type dates and times to real MySQL dates and times.
STR_TO_DATE Example usage (Linux date format converted to MySQL datetime)
You could use this method for times and dates separated or concatenate date and time to one varchar and convert it to mysql datetime. This is actually inverse DATE_FORMAT function.
More info from MySQL str_to_date manual and MySQL date_format manual.
Dear Jr
I have an issue with your class and I can not find my error. Your class works everywhere very fine in my application. Today was working on the payroll sytem of my timesheet application. I used your class in the same manner as i did on other screens withhn my app. now when I want to display the times it looks like:
(362201 hours, 45 minutes) (362207 hours, 45 minutes) (362213 hours, 30 minutes)
on a different page with the same times it comes out normal:
(3 hours, 15 minutes) (4 hours, 45 minutes) (4 hours, 45 minutes)
Can you explain and point me to a solution?
thank you
Hi again Vincent,
It is very hard to say and debug because I don’t know your code exactly where you are using my class.
WOOOO!!!! I was stuck on this problem for a while. Thanks for the help. :)
On one page is working fine and on the other with the same times it runs different?
here is the code of the page where it gives me the wrong format, time_eader.php holds only your class and I include it on a other pages and the times work well!
>>>>> php
include(‘time_reader.php’); <<<php
<<<php
$strDate = trim($_POST['txtDate']);
$strDate2 = trim($_POST['txtDate2']);
$strUsr = $_POST['chkUsrInclude'];
$strQueryAtt=" WHERE TimeSheetFiled 1 “;
$strQueryOrder = ” ORDER BY TimeSheetDate DESC ” ;
if ((strlen($strDate) > 0) AND (strlen($strDate2) =’”. $strDate .”‘ “;
}
if ((strlen($strDate2) >0) AND (strlen($strDate) < 1)){
$strQueryAtt .=" AND TimeSheetDate <= '". $strDate2 ."' ";
}
if (($strDate2 “”) AND ($strDate “”)){
$strQueryAtt .=” AND TimeSheetDate BETWEEN ‘”. $strDate .”‘ AND ‘”. $strDate2 .”‘”;
}
$n=count($strUsr);
if ($n> 0) {
for ($i=0; $i
Start:
<input name="txtDate" type="text" id="txtDate" size="10" maxlength="12" readonly="True" value="” onclick=”scwShow(scwID(‘txtDate’),event);” style=”cursor:hand” />
End:
<input name="txtDate2" type="text" id="txtDate2" size="10" maxlength="12" readonly="True" value="” onclick=”scwShow(scwID(‘txtDate2′),event);” style=”cursor:hand”/>
<<php $strQuery = "SELECT DISTINCT TimeSheetUserID, TimeSheetUsrName FROM `TimesheetTbl` ". $strQueryAtt . " ";
$check_employees_in_Sheets = mysql_query($strQuery) or die(mysql_error());
if(mysql_num_rows($check_employees_in_Sheets) == 0){
echo "no records found in range”;
}else{ ?>
<<<php while($get_employee_sheet_data = mysql_fetch_array($check_employees_in_Sheets)) {
$EmplName = $get_employee_sheet_data['TimeSheetUsrName'];
$EmplID = $get_employee_sheet_data['TimeSheetUserID'];
echo "”. $EmplName . “”;
}
?>
<?php
echo "”;
echo ” “;
echo ” “;
$strQuery = “SELECT * FROM `TimesheetTbl` “. $strQueryAtt . ” “. $strQueryOrder .”";
$rs_empl_filter_Sheets = mysql_query($strQuery) or die(mysql_error());
$i=mysql_num_rows($rs_empl_filter_Sheets);
if($i == 0){
echo “no timesheet records found in range”;
}else{
echo “”;
echo “Timesheets: “. $i .”";
echo “”;
echo ” “;
echo ” “;
echo ” Date”;
echo ” Job”;
echo ” Times”;
echo ” File”;
echo ” “;
echo ” “;
$tc = new TimestampCalc();
while($get_employee_sheet_data = mysql_fetch_array($rs_empl_filter_Sheets)) {
$EmplSheetID = $get_employee_sheet_data['TimeSheetID'];
$EmplSheetDate =$get_employee_sheet_data['TimeSheetDate'];
$EmplSheetJobID = $get_employee_sheet_data['TimeSheetJobTitleID'];
$EmplSheetJobTitle = $get_employee_sheet_data['TimeSheetJobTitle'];
$EmplSheetIn = $get_employee_sheet_data['TimeSheetTimeIn'];
$EmplSheetOut = $get_employee_sheet_data['TimeSheetTimeOut'];
$EmplSheetIn2 = $get_employee_sheet_data['TimeSheetTimeIn2'];
$EmplSheetOut2 = $get_employee_sheet_data['TimeSheetTimeOut2'];
$EmplSheetIn3 = $get_employee_sheet_data['TimeSheetTimeIn3'];
$EmplSheetOut3 = $get_employee_sheet_data['TimeSheetTimeOut3'];
$formattedTime = $tc->addTimeDiff($EmplSheetIn, $EmplSheetOut);
$formattedTime2 = $tc->addTimeDiff($EmplSheetIn2, $EmplSheetOut2);
$formattedTime3 = $tc->addTimeDiff($EmplSheetIn3, $EmplSheetOut3);
$n_total_i = $tc->addTimeDiff($EmplSheetIn,$EmplSheetOut);
$n_total_i_2 = $tc->addTimeDiff($EmplSheetIn2,$EmplSheetOut2);
$n_total_i_3 = $tc->addTimeDiff($EmplSheetIn3,$EmplSheetOut3);
echo “”;
echo “”;
echo ” “;
echo ” “. $EmplSheetDate .”“;
echo ” “. $EmplSheetJobTitle .”";
echo ” (“. $n_total_i .”)”;
if (strlen($n_total_i_2) >0) {
echo ” (“. $n_total_i_2 .”) “;
}
if (strlen($n_total_i_3) >0) {
echo ” (“. $n_total_i_3 .”) “;
}
echo “”;
echo ” “;
echo ” “;
echo ” “;
echo ” “;
echo ” “;
echo ” “;
} // timesheets
echo ” “;
echo ” Total Time: “. $tc->getFormattedTotal() .”";
}
echo “”;
echo “”;
echo “”;
>>>php
PS: each timesheet can hold multiple times.
thanks for your smarts
Jr I found the bug …. .. how strange is this … the only diff on the above page is my sql query what uses select * … I just changed the query and added all the fields names into the query
…
select TimeSheetTimeIn, TimeSheetTimeOut, TimeSheetTimeIn2, TimeSheetTimeOut2, TimeSheetTimeIn3, TimeSheetTimeOut3,
TimeSheetJobTitle, TimeSheetJobTitleID, TimeSheetJobDescription, TimeSheetDate, TimeSheetFiled FROM `TimesheetTbl` ….
and voila your times are formated correctly
Hi Vincent,
And nice to hear that you get it working!
JR, great blog post. Just what I wanted, thanks!
I just have one question about it… is there any way to exclude certain hours from this count? I’m trying to use this script in an environment that counts working hours, and such it should only count 9 out of 24 hours per day (9 AM to 6 PM).
Unfortunately this goes above my head as far as my PHP/function knowledge goes. Any chance you can assist me on this?
Hi Thomas,
Actually this is not best approach on your case. Could you just loop through your working days and count every days hours?
I think you should check PHP: Loop through dates (from date to date) with strtotime() function post.
Please feel free to ask for further guidance, if you need some more?
Well, my situation is as follows:
I have four variables, $date, $time, $enddate and $endtime. These come from a MySQL database and contain stuff like “2011-05-18″ and “13:39:00″ for $date and $time, and “2011-06-12″ and “16:05:00″ for $enddate and $endtime.
What I want to do here is calculate the hours between those dates, but without weekends and non-working hours (6PM to 9 AM, evening). How would this apply to the loop bit?
This is slightly more problematic than what I thought of first.
So you have to get first day 13:39 to 18:00 and next days 9:00 to 18:00 and last day 9:00 to 16:05 weekends excluded?
Yes, like that. I should count all the time that has been passed between time A, date B and time X, date Z. Excluding non-working hours (15 hours each day – 6PM to 9AM) and weekends.
So something like from Friday 4:35PM to Tuesday 11:10AM should result in 13 hours 45 minutes.
Hi again Thomas,
So you mean 12 hours 45 minutes?
But yes here is example code which should work for you. I wrote this class once for Vincent, but reuse it here now… :)
Output, when debug is true
Earlier example case output “2011-05-18 13:39:00″ to “2011-06-12 16:05:00″ (note this end date is Sunday)
I tested this code on Linux command line, so I use “\n” as a line break. If you test this on browser then change line break to
This code is not the most “polished” alternative, but should work at least on the basis of quick testing. :) Of course you could copy idea and make this code to fit your own code ;)
Please let me know, if you have some problems, with this?
Sorry for the late response.
With some small modifications it worked great, thanks very much!
But how would I be able to put the result in a hh:mm:ss format? That would make it perfect ;)
Hi Thomas,
Nice to hear that it worked for you. :)
Try to replace timeFormat function with following:
It should work! ;)
Hi,
I read all the comments + check all the codes but its too complicated for me as I am new.
I want the time diff between time now + $datetime (stored value in sql)
i have 2 variables
1. $datetime — stored timestamps in sql
2. time(); — current date and time stamps
output will be: 20 sec. ago or 1 hrs. ago and after 24 hrs. 1 day ago
how so i get these value? IF you need full code, i can send you or will post here.
Hi,
This original function should work for your case normally just use it like:
Let me know, if you have some problems with this.
Jr,
I would like to first thank you for all of the help that you have been providing to others here. It is not often that one human will go out of his or her way in the ways that you have.
I have a small issue and I am sure that it is related to way to many hours behind the keyboard. The issue is that I am constantly being returned the same incorrect date no matter what the “previous” date is.
For Example:
echo time() . " - " . $row[logonDateTime] . "";
echo "difference is " . (time() - $row['logonDateTime']) . "";
echo time() . " - " . $row[logonDateTime] . "";
echo "difference is " . (time() - $row['logoffDateTime']) . "";
OUTPUT:
1313117467 - 1313053080
difference is 64387
1313117467 - 1313053080
difference is 62827
How ever when I run it through your OP function like:
$lastLogon = dateDiff(time(), $row[logonDateTime]);
echo $lastLogon . "";
$lastLogoff = dateDiff(time(), $row[logoffDateTime]);
echo $lastLogoff . "";
The result is always (regardless of a change in logonDateTime or logoffDateTime)
41 years, 7 months, 11 days, 2 hours, 53 minutes, 51 seconds
41 years, 7 months, 11 days, 2 hours, 53 minutes, 51 seconds
As you can see above when i subtract each of those time stamps from the current time(), A true representation of how many seconds is represented. I am unable to figure out why running it though your function would result in such a consistant inconsistency.
Any suggestions? Before I leave I would like, ore more time, to thank you and applaud you for the time and effort you have put into this one conversation alone. I have been programming in several languages for a while now with php kind of being a bit of a bastard child that i like to take to the park once in a while. In the many years that I have dabbled in programming, I have found less than 3 that were so willing to help the community. I would like to applaud you for your efforts and hope that our fellow humans may see people like you and be more willing to help a neighbor as you have.
Please excuse my typo in the first code listing. It should read:
echo time() . " - " . $row[logonDateTime] . "";
echo "difference is " . (time() - $row['logonDateTime']) . "";
echo time() . " - " . $row[logoffDateTime] . "";
echo "difference is " . (time() - $row['logoffDateTime']) . "";
The only change was the reference to the database item $row[logoffDateTime] on the third line. It had no impact on the output other than to make it a little confusing to read where the data was outputting from. The output above is still accurate as the piece of code that calculated it was correct, just not its label.
Solved
Ok perhaps you have a better solution than what I came up with. The issue came from your first test of is_int(). In my situation where I am being returned a timestamp created by mysql from a datetime filed, php was treating the timestamp as a string. I do not know why it would default to treating a “string” of numbers as a literal string as aposed to one number but i used the following hack to make it work. Do you know of a better way to typecast with a language that has no casting?
$lastLogon = dateDiff(time(), ($row[logonDateTime] + 0));
echo $lastLogon . "";
$lastLogoff = dateDiff(time(), ($row[logoffDateTime] + 0));
echo $lastLogoff . "";
Notice that I have added 0 to the returned timestamp.
Any suggestions?
Better Solution
$lastLogon = dateDiff(time(), (int)$row[logonDateTime]);
echo $lastLogon . "";
$lastLogoff = dateDiff(time(), (int)$row[logoffDateTime]);
echo $lastLogoff . "";
Ok so its official, i have been behind this screen for way too long. Thank you again for your contributions.
Hi Wes,
You got this totally solved? Or do you need some help with this still?
Thank for the function!
I’ve read many dateDiff functions on the internet which don’t contemplate the years problem.
Santiago
Very nice post. I tried writing something myself for my site, but no luck, so I Googled. Your site was 3rd listed and I’m so happy I found it. Bookmarked and waiting for more.
This function makes my life so easy! :) *applauds*
Hi JR
Will you help me also plzzzzzz
My prob is i cant find the diff when the total hours exceeded above 24
that is
Assigned Hours is 30:00:00
Completed hours is 20:00:00
i want to find the difference between these hours
that is
Remaining Hours as 10:00:00
will you please help me as soon as possible
Hi Keerthi,
So you are using only hours, minutes and seconds without days, months and years?
yes…..
if assigned hours or completed hours gets greater than 24:00:00 ,then i’m not able to find the difference.wht will i do to find the difference.
In one of the above codes it shows how to find out the total no of working hours.
After that how can i find the diff between assigned and completed hours??
Plz help me
Hi again Keerthi,
I think best way is simply convert hours, minutes and seconds to seconds and then calculate difference and then convert seconds back to hours, minutes and seconds. I wrote following code to do this:
Function usage:
Output:
This code is only quick example without any input value checks and I assume that the assigned time is always equal or greater than completed time. So this is maybe not production ready code, but I think you get the idea… :)
Thank alot….
it works
thank you so much
You’re welcome! ;)
how can i set a reminder for my insurance policies that reminds me 7 days before the due date of premium. one is yearly and another is monthly. Policies were bought in june 2001(yr) and oct 2007(monthly).
$trime1 = time();
$trime2 = "(".$get_info['dt'].")";
$trime3 = "(".$get_info['lastchange'].")";
if ($get_info['status'] == 3){
$diff = "\t".dateDiff($trime2, $trime3)."\n";
echo $diff;}
else {
$diff = "\t".dateDiff($trime2, $trime1)."\n";
echo $diff;}
Thanks for this function, been scourging around the net for it. But i was having an issue. As you can see on the code above, i’m trying to do a datediff on a row list directly from my SQL database. dt column data type is datetime while lastchange column is timestamp. Result from doing the code above is : 41 years, 10 months, 13 days, 4 hours, 2 minutes, 52 seconds. Since i’m practically not too familiar with php code, may i know whether is there a way for me to tackle this issue? Thanks!
Hi BlackHowling,
Could you also post exact values (MySQL datetime and timestamp), what you get from MySQL database?
Looks some problem with datetime data type, but if you could “echo” those values and post here…
Will do.
These are 3 example values from DT column (datetime data type) based on my original SQL query made for the project that i’m currently doing (a total of 100 rows).
A1 2011-11-14 14:57:32
A2 2011-11-14 14:36:05
A3 2011-11-14 14:13:21
and these would be the lastchange which is in timestamp datatype,
B1 2011-11-14 15:11:10
B2 2011-11-14 15:12:10
B3 2011-11-14 14:13:21
Basically im trying to pull of an aging column, which your function will work as the function to calculate the aging, for example, B1 – A1, B2 – A2 and lastly B3 – A1. So it will print out the aging period of each row A1, A2, A3… etc. Seeing the format is basically the same in the data, it shouldn’t be an issue right? I’ve also tried Wes’s method, but failed. :(
If I try run dateDiff function with your values:
I get following output:
Note the last one is empty, because there is no difference…
So I’m not sure anymore, what is the problem? :)
Thank you for your time, by the way. Really appreciated. Anyway, the issue lies at it doesn’t want to calculate my SQL queries unless i put up the values inside of it which i can’t because the data was updated every half an hour. Therefor, i was trying to make the function to auto calculate the column and print out a result on a new row for it, perpendicular to the data that was listed. Let me give you the link of a test page i made. http://support2.netmyne.com/testing.php (while it’s still there). As you can see, instead of publishing it in a new row, it decides to give up and print the Aging (the one where i used the function) down below, calculating god knows what.
Thanks! Now I got it, what you are doing… :)
But if you want print that aging every rows then, I think it is not big problem…just run dateDiff function once per every row with your timestamps?
Thanks. Let me try a simple php method based on that logic.
Let’s say the table “test” contains dt(dateTime), lastchange(timestamp), and status(to check for open/resolved).
Example,
“SELECT dt,lastchange,status FROM test ORDER BY dt DESC LIMIT 100″ would be the SQL query to get the latest data sorted by the latest data accordingly to the dt column,
Full code would be;
$time2) {
$ttime = $time1;
$time1 = $time2;
$time2 = $ttime;
}
// Set up intervals and diffs arrays
$intervals = array('year','month','day','hour','minute','second');
$diffs = array();
// Loop thru all intervals
foreach ($intervals as $interval) {
// Set default diff to 0
$diffs[$interval] = 0;
// Create temp time from time1 and interval
$ttime = strtotime("+1 " . $interval, $time1);
// Loop until temp time is smaller than time2
while ($time2 >= $ttime) {
$time1 = $ttime;
$diffs[$interval]++;
// Create new temp time from time1 and interval
$ttime = strtotime("+1 " . $interval, $time1);
}
}
$count = 0;
$times = array();
// Loop thru all diffs
foreach ($diffs as $interval => $value) {
// Break if we have needed precission
if ($count >= $precision) {
break;
}
// Add value and interval
// if value is bigger than 0
if ($value > 0) {
// Add s if value is not 1
if ($value != 1) {
$interval .= "s";
}
// Add value and interval to times array
$times[] = $value . " " . $interval;
$count++;
}
}
// Return string with times
return implode(", ", $times);
}
$result = mysql_query("SELECT dt,lastchange,status FROM test ORDER BY dt DESC LIMIT 100");
echo "
Date Receive Rating
Last Change
Aging
";
while($row = mysql_fetch_array($result))
{
echo "";
echo "" . $row['dt'] . "";
echo "" . $row['lastchange'] . "";
$trime1 = time();
$trime2 = "(".$row['dt'].")";
$trime3 = "(".$row['lastchange'].")";
if ($get_info['status'] == 3){
$diff = "\t".dateDiff($trime2, $trime3)."\n";
echo $diff;}
else {
$diff = "\t".dateDiff($trime2, $trime1)."\n";
echo $diff;}
echo "";
}
echo "";
mysql_close($con);
?>
http://support2.netmyne.com/testing.php still getting the same result :( /chugs a beer. i just don’t understand why it total out the aging, and print it on every single row, lol.
Thanks! Now I finally see where the problem is… :)
The problem is brackets. Let’s see…following:
Should be simply:
Do you get it working now? :D
That’s it! OH MY GOD! SUCH SIMPLE THING ! D: Thank you very much, good sir! In the end it was my coding’s fault! I apologized! D: Thanks! /toss a beer
New Result :
2011-11-15 14:21:02 2011-11-15 14:23:13 2 hours, 23 seconds
2011-11-15 13:55:30 2011-11-15 14:17:05 2 hours, 25 minutes, 55 seconds
2011-11-15 12:13:43 2011-11-15 13:24:59 4 hours, 7 minutes, 42 seconds
You are welcome! Yes, very simple thing, but hard to find… :D Funniest thing is that you posted it on your first post… :)
And no problems! :) It’s most important that you got it working as it should be! ;D
hello. wonderful script.
I am trying to find the difference between a given date, that can be from the past or from the future, and the current date. But the current script only says the difference. It does not say for example 14 days ago, or 14 days left. How can I do that? How can find a non-absolute difference in days only. The output can be in negative if the given date is from the past and positive if the given date is from the future. I am trying to find the difference in days so i dont need all the year, min, seconds, month variables. Thanks
Abu
Hi Abu,
Thanks!
This is totally new topic and off topic, so could you please post your question to our forums -> PHP Board let’s see what we could do. It’s better place to discuss anyways. :)
@JR.
ok. I did.
Thanks.
Abu
Thanks Abu! :) I will check your problem soon…
Why not use the native functionality? The format function in the DateTime class can be used to output the same information with just a few lines of code.
$now = new DateTime('now');
$then = new DateTime($date);
$diff = $now->diff($then);
echo $diff->format('%a days');
Hi Charlie,
Thanks, I actually post this style solution here and also native MySQL example. ;)
I love you code JR it’s really functional but is there a way I can get the difference ONLY in one of the time.
For example, i want the following:
difference between 2011-12-14 21:54 and 2011-12-16 20:45
— if i need it in HOURS then it will give for example 22.8 Hours
— if i need it in MINUTES for examples it will return 1368
and so on??
if we were able to to this it will HELP me alot.
THANKS AGAIN
Sevag
Hi Sevag,
What intervals you want to use? Seconds, minutes, hours, days…?
Years
Month
Week
Day
Hour
Minutes
I need this for the following reason
If my client asked for service every 10 minutes between 2011-12-16 10:00 till 2011-12-17 10:25
Since he picked minutes as interval then i want something that gives me in this case 1465.
Then i will do simply 1465 / (10) = 14.65. So this means 14 services.
Now if he were same time interval but he picked every 2 hours
Then the formula should give me 24.2
Then i do 24.2 / 2 = 12.1 . so this means 12 services.
Sorry 1465/10 = 146.5 => 146 services
Hi again Sevag,
Do you need output example as 24.2 hours or is just 24 hours integer value enough? This full double/floating point value with decimals is easy to get with minute, hour, day, week intervals, but it’s very hard to get with month and year intervals, because we can’t use fixed seconds for month and year. If you want to use this date diff function logic and accuracy, then it’s only possible to get integer values.
just the integer value is enough
but supposing minutes interval
instead of getting
1 day 3 minutes
I get
1443 minutes
Okey :) Then check following code:
Output:
Note. first examples use your timestamps and last examples use date 2014-06-17… :)
I just tested this quickly and seems to be working, please let me know, if you have any problems with that?
First of all thank you for your code, it helped me alot. But i just realized something that got me puzzled.
Suppose I have the following two time-stamps:
$start =’2011-12-18 23:19:00′;
$end =’2012-02-08 13:20:00′;
$interval=3;
I tried to compute the difference in hours using two different approaches and I got a small difference.
1.
$howmany=floor($difference/($interval*60*60)+1);
output was 413
2.$howmany=(dateDiff( $start , $end , ‘hour’)/$interval)+1;
out was 414
I tried the same two approaches for minutes, days, and weeks and answers were IDENTICAL. but just never figured out why in this specific case answers weren’t the same. Any suggestions?
Thank you,
Sevag
Actually, I can’t see the problem here, so let’s look at this in more detail…
First if we compare just fixed value approach, with dateDiff:
Output:
So this looks good, exactly same, but dateDiff output without decimals, as it should be.
Then divide results with three (your interval):
1238.0166666667 / 3 = 412.672222222
1238 / 3 = 412.666666667
Then add one (I don’t know why, but if you just have to add one):
412.672222222 + 1 = 413.672222222
412.666666667 + 1 = 413.666666667
Then you use floor to round first value fractions down:
floor(413.672222222) = 413
413.666666667
So actually second value is 413.666666667 at this point, not 414…and first value fractions is rounded down and it’s 413…
you are great , your code and function is very useful
Thanks to help all
Very nice function. This is useful when the PHP version < 5.3. Since version 5.3, PHP supports method Datetime::diff( $datetime1, $datetime2 ); that might be an easier solution.
Hi Rilwis nice to see you here,
Yes, this is old post and PHP’s own Datetime:diff is useful on PHP 5.3, but you still need to format output manually. And of course here is many custom modifications from original version… ;)
hi all,
I have a question to all,
How to calculate minutes “Operational Hours” within a period.
case example :
Date range : 2011-11-01 to 2011-11-30,
Non Operational Hours : between 22:00 to 08:00 week day (Mon to Frid)
Non Operational Days : Sat + Sun
Quest :
How to Calculate Total “Minutes” Operational Time ??
Please help,
thanks for your advice …
BP
Hi abang,
Is those Operational days always from Mon to Fri?
And is those hours fixed 08:00 – 22:00?
Heej JR, your script has helped me loads. Thanks thus far! I have a quick question, a problem I can’t simply solve by myself.
If I do:
echo dateDiff(1267074000, time(), 3);
it works fine.
But if I do:
echo dateDiff($setTime, $currentTime, 3);
it doesn’t work, even though holding the same results.
Is there anything I’m doing wrong?
Cheers and much thanks in advance.
Forgot to add: it gives me 42 years, xx days, etc. I can’t figure out why.
Hi Ben,
Could you echo your variables $setTime and $currentTime, just before deteDiff function and post output here, like:
Just pinched this for something too. Thanks a lot mate, works very well!
Beginning of the function is hidden because of remarks in code :)
oops, now looks good, looks like something loading slowly
I hate to bring up a really old post but this has been extremely helpful with my current project. I am doing a project that calculates tenure. An employee can work full-time, or a percentage of time. For example if the employee worked between 01/01/01 and 01/01/02 at full-time I need it to have the result as 1 year but if the employee only worked, say 20 of 40 hours a week (50%), then I should get a result of 6 months. I feel that I should be able to modify the given code to include this but I am still learning PHP and I am having more trouble than I care to admit. Is there any way you or someone else could help me?
Thank you again.
Hi Jordan,
Do you want to get finally exact weeks, days, hours, minutes? And do you have always full months and years?
What I really need is just years months and days. between the two dates and then a total amount of days.
Do i always have full months and years? Yes the dates will always be with full months and years.
Hi Jordan,
It’s actually very easy to get just total amount of days between two timestamps with this function just change following line:
To:
And if you want years, months and days then change it to:
You can use this array as a parameter or use simple if…else structure to get it changed using parameter if you want use same function for both.
Hi JR..!
Thank’s for sharing this great script of yours, its very helpful!
You just saved me from being stuck for days..
Keep up the good work!
Thank you so much..!^__^
planetjane414
Very helpful, nice post Cheers :)