php "countdown til" and "since time" GMT UTC time function - php

I'm working with a function I found to do this, but I'm trying to make it work with a GMT utc timestamp:
EDIT:
Maybe my issue is with how i'm "converting" the user input time to GMT...
I was doing
$the_user_input_date = strtotime('2011-07-20T01:13:00');
$utctime = gmdate('Y-m-d H:i:s',$the_user_input_date);
Does gmdate('Y-m-d H:i:s',$the_user_input_date); not actually "convert" it to gmt? does it just format it? Maybe thats my issue.
Here's what the times I can supply would look like:
//local time in GMT
2011-07-20T01:13:00
//future time in GMT
2011-07-20T19:49:39
I'm trying to get this to work like:
Started 36 mins ago
Will start in 33 mins
Will start in 6 hrs 21 mins
Will start in 4 days 4 hrs 33 mins
Here's what im working with so far:
EDIT: new php code im working with, seems to ADD 10 HOURS on to my date. Any ideas? I updated it here:
function ago($from)
{
$to = time();
$to = (($to === null) ? (time()) : ($to));
$to = ((is_int($to)) ? ($to) : (strtotime($to)));
$from = ((is_int($from)) ? ($from) : (strtotime($from)));
$units = array
(
"year" => 29030400, // seconds in a year (12 months)
"month" => 2419200, // seconds in a month (4 weeks)
"week" => 604800, // seconds in a week (7 days)
"day" => 86400, // seconds in a day (24 hours)
"hour" => 3600, // seconds in an hour (60 minutes)
"minute" => 60, // seconds in a minute (60 seconds)
"second" => 1 // 1 second
);
$diff = abs($from - $to);
$suffix = (($from > $to) ? ("from now") : ("ago"));
foreach($units as $unit => $mult)
if($diff >= $mult)
{
$and = (($mult != 1) ? ("") : ("and "));
$output .= ", ".$and.intval($diff / $mult)." ".$unit.((intval($diff / $mult) == 1) ? ("") : ("s"));
$diff -= intval($diff / $mult) * $mult;
}
$output .= " ".$suffix;
$output = substr($output, strlen(", "));
return $output;
}
#Jason
I tried what you suggested here:
function ago($dateto)
{
$datetime1 = new DateTime( $dateto);
$datetime2 = new DateTime();
$interval = $datetime1->diff($datetime2);
// print_r($interval);
$format = '';
if ($interval->h) {
$format .= ' %h ' . ($interval->h == 1 ? 'hour' : 'hours');
}
if ($interval->i) {
$format .= ' %i ' . ($interval->i == 1 ? 'minute' : 'minutes');
}
// more logic for each interval
if ($format) {
echo $interval->format($format), ' ago';
}
else {
echo 'now';
}
}
It always seems to add 10 hours on to my time.
Any ideas what could be going on?
Maybe an error lies with how I'm saving the target time?
When someone submits a time its converted and stored like this
The user submitted time will always start out looking like this as their local time:
07/20/2011 11:00 pm
Then:
$time = mysql_real_escape_string($_POST['time']);
$the_date = strtotime($time);
//make user input time into GMT time
$utctime = gmdate('Y/m/d H:i:s',$the_date);
$query = "INSERT INTO $table (time) VALUES ('$utctime');";
mysql_query($query);

Provided you have access to PHP >= 5.3 I'd recommend DateTime::diff(). The DateInterval returned gives you all the parts you would need for display as well as has its own methods, such as format().
Here's a sample to give you an idea. There are more complete samples in the comments of the PHP documentation links.
<?php
$datetime1 = new DateTime('2011-07-20');
$datetime2 = new DateTime();
$interval = $datetime1->diff($datetime2);
// print_r($interval);
$format = '';
if ($interval->h) {
$format .= ' %h ' . ($interval->h == 1 ? 'hour' : 'hours');
}
if ($interval->i) {
$format .= ' %i ' . ($interval->i == 1 ? 'minute' : 'minutes');
}
// more logic for each interval
if ($format) {
echo $interval->format($format), ' ago';
}
else {
echo 'now';
}
It outputs (on my system):
22 hours 10 minutes ago

Your $datefrom is a string, but $dateto is an int. You can't subtract them that way.
Instead of:
$datefrom=gmdate("Y/m/d\TH:i:s\Z");
Do:
$datefrom=time();
PS. I did not check the rest of the code.

Related

How to get minutes in the form of hours days weeks months years PHP [duplicate]

This question already has answers here:
How to calculate the difference between two dates using PHP?
(34 answers)
Closed 3 years ago.
I am struggling very hard to achieve this but the results are not what i am trying to get.The result values are wrong and the colons are not on their proper place when using random minute values(that should generate years : months : weeks : days : hours : minutes) from such as 1500, 2800 .etc
I want to convert Minutes into respective years : months : weeks : days : hours : minutes
What i have tried?
$minutesConverter = function($from,$to,$format='dynamic'){
$year = floor($from/525600) ? floor($from/525600) : '';
$Rminutes= $from%525600;
$month = floor($Rminutes/43800.048) ? floor($Rminutes/43800.048) : '';
$Rminutes= $from%43800.048;
$week = floor($Rminutes/10080) ? floor($Rminutes/10080) : '';
$Rminutes= $from%10080;
$day = floor($Rminutes/1440) ? floor($Rminutes/1440) : '';
$Rminutes= $from%1440;
$hour = floor($Rminutes/60) ? floor($Rminutes/60) : '';
$minute = $from%60 ? $from%60 : '';
if(!empty($year) ){ if($year > 1 ){ $year = $year.' years'; }else{ $year = $year.' year'; } }
if(!empty($month) ){ if($month > 1 ){ $month = $month.' months'; }else{ $month = $month.' month'; } }
if(!empty($week) ){ if($week > 1 ){ $week = $week.' weeks'; }else{ $week = $week.' week'; } }
if(!empty($day) ){ if($day > 1 ){ $day = $day.' days'; }else{ $day = $day.' day'; } }
if(!empty($hour) ){ if($hour > 1 ){ $hour = $hour.' hours'; }else{ $hour = $hour.' hour'; } }
if(!empty($minute)){ if($minute > 1 ){ $minute = $minute.' minutes'; }else{ $minute = $minute.' minute'; } }
if(!empty($year)) { $year = $year; }
if(!empty($month)) { if(empty($year)){ $month = $month; }else{ $month = ' : '.$month; } }
if(!empty($week)) { if(empty($month)){ $week = $week; }else{ $week = ' : '.$week; } }
if(!empty($day)) { if(empty($week)){ $day = $day; }else{ $day = ' : '.$day; } }
if(!empty($hour)) { if(empty($day)){ $hour = $hour; }else{ $hour = ' : '.$hour; } }
if(!empty($minute)) { if(empty($hour)){ $minute = $minute; }else{ $minute = ' : '.$minute; } }
return $year.$month.$week.$day.$hour.$minute;
};
Example:
For using minute value as 131400 i,e 3 Months(according to google calculator) But the output of this is:
2 months6 hours
Problems?
No colons
Wrong Readable time
Help Needed ! Kindly take a look.
The main issue with your code is that you should be subtracting the number of periods times the period length from $from on each pass, not taking the modulus of $from with the period length. This is because not all your periods are multiples of all the smaller ones (e.g. 1 month is not an exact multiple of weeks). The code can also be signficantly simplified by the use of an array of periods, for example:
$minutesConverter = function($from) {
if (!$from) return '0 minutes';
$periods = array('year' => 525600,
'month' => 43800,
'week' => 10080,
'day' => 1440,
'hour' => 60,
'minute' => 1);
$output = array();
foreach ($periods as $period_name => $period) {
$num_periods = floor($from / $period);
if ($num_periods > 1) {
$output[] = "$num_periods {$period_name}s";
}
elseif ($num_periods > 0) {
$output[] = "$num_periods {$period_name}";
}
$from -= $num_periods * $period;
}
return implode(' : ', $output);
};
echo $minutesConverter(131390, 0);
Output:
2 months : 4 weeks : 2 days : 9 hours : 50 minutes
Demo on 3v4l.org
Not a direct answer to your question, but maybe an idea and a template.
I had a similar problem years ago. I wanted to display a duration (time stamp into the past) as relative time. So I create the function below and had the following prerequisites:
Short format.
Fixed field width (6+strlen(separator)).
No month, because the length of month varies too much.
Units are the abbreviations of seconds, minutes, hours, days, weeks and years.
Support of german and english abbreviations.
Limit the output to 2 units. More doesn't help a reader.
Option separator between 2 units.
And here is my function:
function GetAge6 ( $sec, $sep = '' )
{
if ( $sec < 60 )
return sprintf(' %s%2us',$sep,$sec);
$min = floor($sec/60);
if ( $min < 60 )
return sprintf('%2um%s%02us',$min,$sep,$sec%60);
$hour = floor($min/60);
if ( $hour < 48 )
return sprintf('%2uh%s%02um',$hour,$sep,$min%60);
$day = floor($hour/24);
if ( $day < 28 )
return sprintf('%2ud%s%02uh',$day,$sep,$hour%24);
$week = floor($day/7);
if ( $week < 52 )
return sprintf('%2uw%s%2ud',$week,$sep,$day%7);
$year = floor($day/365);
if ( $year < 100 )
{
$week = floor( ( $day - $year*365 ) / 7 );
return sprintf('%2u%s%s%02uw',
$year, DCLIB_LANGUAGE=='de' ? 'j' : 'y', $sep, $week );
}
if ( $year < 1000000 )
return sprintf('%s%6u%s',
str_repeat(' ',strlen($sep)),
$year, DCLIB_LANGUAGE=='de' ? 'j' : 'y' );
return sprintf('***%s***',$sep);
}
And here is an example: https://wiimmfi.de/stats/login/ext#hour
See column average online duration and the hover texts.
If you use composer (https://getcomposer.org) I recommend using the Carbon package for dates and such. Maybe you and others will find this interesting:
https://carbon.nesbot.com/docs/#api-difference
It also has difference for humans, if you would like something like: "1 hour ago".
https://carbon.nesbot.com/docs/#api-humandiff
This is also the package used by the Laravel framework and it is awesome. But if you're trying to learn new stuff, I would definitely convert all into seconds before calculating and start with the highest amount and so on.

Should I store the result of an function into an array?

I have a function like this:
function time_elapsed_string($ptime)
{
$date_time = strtotime("1348-10-10 04:30:01") + $ptime;
$year = date("Y",$date_time);
$month = date("m",$date_time);
$day = date("d",$date_time);
$time = date("H:i:s",$date_time);
$etime = time() - $ptime + 1;
$a = array( 31536000 => 'year',
2592000 => 'month',
86400 => 'day',
3600 => 'hour',
60 => 'minute',
1 => 'second'
);
foreach ($a as $secs => $str)
{
$d = $etime / $secs;
if ($d >= 1)
{
$r = round($d);
// EX:
return array('date' => $day.'-'.$month.'-'.$year, // 2016-02-20
'time' => $time, // 03:30:04
'difference' => $r . ' ' . $str . ' ago' // 2 month ago
);
}
}
}
And I use it like this:
$ptime = 1470692661;
$html = '<span title="date: '.time_elapsed_string($ptime)['date'].' time: '.time_elapsed_string($ptime)['time'].'">in '.time_elapsed_string($ptime)['difference'].'<span>';
As you see, I'm using of that function's result like this:
time_elapsed_string($ptime)['date']
ime_elapsed_string($ptime)['time']
time_elapsed_string($ptime)['difference']
In fact I'm calling that function every time I need one of its results. Is that right? Or should I call it once and store it into an array?
Note: My code works as well.
Counting time elapsed since some date/time like this is mauvais ton.
DateTime has been available since PHP 5.2.0 and tonns of people underestimate it. Why don't you use this instead of loops and ifs?
$create_time = "2016-08-02 12:35:04";
$current_time="2016-08-02 16:16:02";
$dtCurrent = DateTime::createFromFormat('Y-m-d H:i:s', $current_time);
// to use current timestamp, use the following:
//$dtCurrent = new DateTime();
$dtCreate = DateTime::createFromFormat('Y-m-d H:i:s', $create_time);
$diff = $dtCurrent->diff($dtCreate);
Now, you can format the result however you want:
$interval = $diff->format("%h hours %i minutes %s seconds");
This will give a clean 3 hours 40 minutes 58 seconds without any arrays, which is better.
UPDATE
There is a general solution to get hours / minutes / seconds via regex:
$interval = $diff->format("%y years %m months %d days %h hours %i minutes %s seconds");
// now remove zero values
$interval = preg_replace('/(^0| 0) (years|months|days|hours|minutes|seconds)/', '', $interval);
UPDATE 2
As of your comment:
Look, I want to use your approach .. but I really cannot implement it .. Actually I need three things: time, date, difference ..! But your approach doesn't give me them..
Well, we already know how to get the difference, it's the $interval variable described above.
To get time and date, you can get it from the $dtCreate variable by, again, using format:
$time = $dtCreate->format('H:i:s');
$date = $dtCreate->format('d-m-Y');
This is a no brainer.
Yes - store the function call result of time_elapsed_string($ptime) in an array, then use that to access your results. You're wasting CPU cycles otherwise!
// call it once
$result = time_elapsed_string($ptime);
// then use:
$result['date'];
$result['time'];
$result['difference'];

Subtracting time to post how many minutes ago [duplicate]

This question already has answers here:
Calculate relative time in C#
(41 answers)
How to display "12 minutes ago" etc in a PHP webpage? [closed]
(3 answers)
Closed 8 years ago.
So my current $item['date'] function gets the time and date of the post in this format Y-m-d H:i:s.
I want to display how many minutes was the post posted or if it is more than 24 hours, how many days ago was it posted OR like 0 days and 20 hours ago? something like that
Why doesn't the minus operator work here my code?
My current code:
<p><?php echo date('Y-m-d H:i:s') - $item['date'] ?> minutes ago</p>
I usually use this function. Use it like this time_ago('2014-12-03 16:25:26')
function time_ago($date){
$retval = NULL;
$granularity=2;
$date = strtotime($date);
$difference = time() - $date;
$periods = array('decade' => 315360000,
'year' => 31536000,
'month' => 2628000,
'week' => 604800,
'day' => 86400,
'hour' => 3600,
'minute' => 60,
'second' => 1);
foreach ($periods as $key => $value)
{
if ($difference >= $value)
{
$time = round($difference/$value);
$difference %= $value;
$retval .= ($retval ? ' ' : '').$time.' ';
$retval .= (($time > 1) ? $key.'s' : $key);
$granularity--;
}
if ($granularity == '0') { break; }
}
return $retval.' ago';
}
What you need to do is convert both dates to timestamp first and substract your original post date from current date and reconvert it back to your desired format. As an example see below.
$now = time();
$datePosted = strtotime($item['date']);
$timePassed = $now - $datePosted;
$agoMinutes = $timePassed/60; //this will give you how many minutes passed
$agoHours = $agoMinutes/60; //this will give you how many hours passed
$agoDays = $agoHours/24; // this will give you how many days passed
And so on ...
Php's timestamp gives date in seconds so it is easier to calculate and work on it if you need mathematical operations.

Convert dates to hours

I'm trying to work with dates for the first time, I did it something about that with Flash but it's different.
I have two different dates and I'd like to see the difference in hours and days with them, I've found too many examples but not what I'm loking for:
<?php
$now_date = strtotime (date ('Y-m-d H:i:s')); // the current date
$key_date = strtotime (date ("2009-11-21 14:08:42"));
print date ($now_date - $key_date);
// it returns an integer like 5813, 5814, 5815, etc... (I presume they are seconds)
?>
How can I convert it to hours or to days?
The DateTime diff function returns a DateInterval object. This object consists of variabeles related to the difference. You can query the days, hours, minutes, seconds just like in the example above.
Example:
<?php
$dateObject = new DateTime(); // No arguments means 'now'
$otherDateObject = new DateTime('2008-08-14 03:14:15');
$diffObject = $dateObject->diff($otherDateObject));
echo "Days of difference: ". $diffObject->days;
?>
See the manual about DateTime.
Sadly, it's a PHP 5.3> only feature.
Well, you can always use date_diff, but that is only for PHP 5.3.0+
The alternative would be math.
How can I convert it [seconds] to hours or to days?
There are 60 seconds per minute, which means there are 3600 seconds per hour.
$hours = $seconds/3600;
And, of course, if you need days ...
$days = $hours/24;
If you dont have PHP5.3 you could use this method from userland (taken from WebDeveloper.com)
function date_time_diff($start, $end, $date_only = true) // $start and $end as timestamps
{
if ($start < $end) {
list($end, $start) = array($start, $end);
}
$result = array('years' => 0, 'months' => 0, 'days' => 0);
if (!$date_only) {
$result = array_merge($result, array('hours' => 0, 'minutes' => 0, 'seconds' => 0));
}
foreach ($result as $period => $value) {
while (($start = strtotime('-1 ' . $period, $start)) >= $end) {
$result[$period]++;
}
$start = strtotime('+1 ' . $period, $start);
}
return $result;
}
$date_1 = strtotime('2005-07-31');
$date_2 = time();
$diff = date_time_diff($date_1, $date_2);
foreach ($diff as $key => $val) {
echo $val . ' ' . $key . ' ';
}
// Displays:
// 3 years 4 months 11 days
TheGrandWazoo mentioned a method for php 5.3>. For lower versions you can devide the number of seconds between the two dates with the number of seconds in a day to find the number of days.
For days, you do:
$days = floor(($now_date - $key_date) / (60 * 60 * 24))
If you want to know how many hours are still left, you can use the modulo operator (%)
$hours = floor((($now_date - $key_date) % * (60 * 60 * 24)) / 60 * 60)
<?php
$now_date = strtotime (date ('Y-m-d H:i:s')); // the current date
$key_date = strtotime (date ("2009-11-21 14:08:42"));
$diff = $now_date - $key_date;
$days = floor($diff/(60*60*24));
$hours = floor(($diff-($days*60*60*24))/(60*60));
print $days." ".$hours." difference";
?>
I prefer to use epoch/unix time deltas. Time represented in seconds and as such you can very quickly divide by 3600 for hours and divide by 24*3600=86400 for days.

Unix timestamp to days, hours, minutes

So, I have a field in my users table named last_active which updates every time a user reloads a page. It's stored in unix timestamp.
I would like to output it like this: Last online: 4 d 18 h 19 m ago
How would one do that? Can you do it with php's date()?
Thank you.
You could achieve this directly in MySQL if you like:
select date_format(from_unixtime(current_timestamp - last_timestamp),
'Last online: %e days, %k hours, %i minutes, %s seconds ago.');
(current_timestamp can be replaced with unix_timestamp(now()) if you want it calculated in-place)
DATE_FORMAT allows you to have a custom string based on a specific date. If you populate its date with the difference between two timestamps, it will work as you've asked.
The above solution will only work if it's under a month; if you want days of the year, use %j. The documentation for the function shows more.
The simplest approach to this is to take the last_active timestamp, and the current timestamp with time(). Then subtract the last active from the current timestamp, and then you simply divide the result with the amount of seconds in a day to get difference in days, amount of seconds in an hour to get difference in hours and so on.
This approach may be slightly inaccurate in some special cases (leap years, etc.) but it should suffice for your simpler usecase
After finding dozens of broken or half-there solutions, I built the following function for UNIX timestamps.
You can limit the detail level ...
echo timeDiff(1350297908); will show "5 minutes, 42 seconds ago".
echo timeDiff(1350297908, 1); will just show "5 minutes ago".
function timeDiff( $from, $levels=7 ){
$now = time();
$diff = ($from > $now) ? $from - $now : $now - $from;
$status = ($from > $now) ? ' away' : ' ago';
$times = array(31536000, 2628000, 604800, 86400, 3600, 60, 1);
$words = array('year', 'month', 'week', 'day', 'hour', 'minute', 'second');
$str = array();
foreach ($times as $k=>$v){
$val = floor($diff/$v);
if ($val) {
$str[] = $val .' '. $words[$k] . ($val==1 ? '' : 's');
$levels--;
}
$diff %= $v;
if ($levels==0) break;
}
return implode(', ', $str) . $status;
}
I wrote this simple function when I need this kind of solution (it gets minutes as input):
function minutes_to_time($minutes)
{
$obj = "";
// extract days
$days = floor($minutes/(1440)); # Divide on the daily minutes 60 min * 24 hours
# echo "Days: " . $days;
// extract hours
$hours = floor(($minutes-($days*1440))/60);
# echo " Hours: " . $hours;
// extract left minutes
$minutes = ($minutes-($days*24*60)-($hours*60));
# echo " Minutes: " . $minutes;
if ($days > 0)
{
$obj .= $days . "d ";
}
if ($hours > 0)
{
$obj .= $hours . "h ";
}
if ($minutes >= 0)
{
$obj .= $minutes . "m ";
}
$obj .= "ago";
return $obj;
}

Categories