PHP: Producing Relative Date/Time from Timestamps

PHP: producing relative date/time from timestamps

This function gives you "1 hour ago" or "Tomorrow" like results between 'now' and 'specific timestamp'.

function time2str($ts)
{
if(!ctype_digit($ts))
$ts = strtotime($ts);

$diff = time() - $ts;
if($diff == 0)
return 'now';
elseif($diff > 0)
{
$day_diff = floor($diff / 86400);
if($day_diff == 0)
{
if($diff < 60) return 'just now';
if($diff < 120) return '1 minute ago';
if($diff < 3600) return floor($diff / 60) . ' minutes ago';
if($diff < 7200) return '1 hour ago';
if($diff < 86400) return floor($diff / 3600) . ' hours ago';
}
if($day_diff == 1) return 'Yesterday';
if($day_diff < 7) return $day_diff . ' days ago';
if($day_diff < 31) return ceil($day_diff / 7) . ' weeks ago';
if($day_diff < 60) return 'last month';
return date('F Y', $ts);
}
else
{
$diff = abs($diff);
$day_diff = floor($diff / 86400);
if($day_diff == 0)
{
if($diff < 120) return 'in a minute';
if($diff < 3600) return 'in ' . floor($diff / 60) . ' minutes';
if($diff < 7200) return 'in an hour';
if($diff < 86400) return 'in ' . floor($diff / 3600) . ' hours';
}
if($day_diff == 1) return 'Tomorrow';
if($day_diff < 4) return date('l', $ts);
if($day_diff < 7 + (7 - date('w'))) return 'next week';
if(ceil($day_diff / 7) < 4) return 'in ' . ceil($day_diff / 7) . ' weeks';
if(date('n', $ts) == date('n') + 1) return 'next month';
return date('F Y', $ts);
}
}

Get relative date from the NOW() function

Use TIMESTAMPDIFF() function. See example:

SELECT
TIMESTAMPDIFF(SECOND, `stamp_column`, NOW()) as `seconds`
FROM
`YourTable`

Or use this stored function:

CREATE FUNCTION `PassedSince`(`stamp` TIMESTAMP)
RETURNS VARCHAR(100)
DETERMINISTIC
BEGIN
DECLARE `result` VARCHAR(100) DEFAULT '';
DECLARE `seconds`, `minutes`, `hours`, `days` INT;

SET `seconds` = TIMESTAMPDIFF(SECOND, `stamp`, NOW());

SET `days` = `seconds` DIV (24 * 60 * 60);
SET `seconds` = `seconds` MOD (24 * 60 * 60);

IF `days` > 0
THEN SET `result` = CONCAT(`result`, `days`, ' Days ');
END IF;

SET `hours` = `seconds` DIV (60 * 60);
SET `seconds` = `seconds` MOD (60 * 60);

IF `hours` > 0
THEN SET `result` = CONCAT(`result`, `hours`, ' Hours ');
END IF;

SET `minutes` = `seconds` DIV 60;
SET `seconds` = `seconds` MOD 60;

IF `minutes` > 0
THEN SET `result` = CONCAT(`result`, `minutes`, ' Minutes ');
END IF;

IF `seconds` > 0
THEN SET `result` = CONCAT(`result`, `seconds`, ' Seconds ');
END IF;

RETURN TRIM(`result`);
END

For query:

SELECT
`PassedSince`('2013-06-19 08:00') as `result`
UNION ALL
SELECT
`PassedSince`('2013-01-01 00:00')

Shows:

result
--------------------------------------
1 Hours 20 Minutes 55 Seconds
169 Days 9 Hours 20 Minutes 55 Seconds

Print out Relative Date / Time from SQL / PHP Datestamp

Found this after two seconds of Google http://www.mdj.us/web-development/php-programming/another-variation-on-the-time-ago-php-function-use-mysqls-datetime-field-type

In general you chose a unit of time like seconds, test if the time-difference is smaller then the max-value for this unit (60s) and if so, print out "$timeDifference $unit". If not you divide the difference by the units max-value and start over with the next higher unit (minutes).

Example:

$timeDif = 60*60*5 + 45; // == 5 hours 45 seconds

// 60 seconds in a minute
if ($timeDif < 60) // false
return "$timeDif second(s) ago";

// convert seconds to minutes
$timeDif = floor($timeDif / 60); // == 300 = 5 * 60

// 60 minutes in an hour
if ($timeDif < 60) // false
return "$timeDif minute(s) ago";

// convert minutes to hours
$timeDif = floor($timeDif / 60); // == 5

// 24 hours in a day
if ($timeDif < 24)
return "$timeDif hour(s) ago";

// ...

Event Relative Time

First of all, let's summarise the expected local values for 1477762205 Unix timestamp:

  • UTC: 17:30:05 (UTC, +0000)
  • London: 18:30:05 (BST, +0100 aka 3600, DST=1)
  • Madrid: 19:30:05 (CEST, +0200 aka 7200, DST=1)

Stuff seems to work as expected as long as you use city-based time zone identifiers:

foreach (['UTC', 'Europe/London', 'Europe/Madrid'] as $time_zone_id) {
$dt = new DateTime('@1477762205');
$tz = new DateTimeZone($time_zone_id);
$dt->setTimezone($tz);
echo $time_zone_id . ': ' . $dt->format('H:i:s [e=T, O]') . PHP_EOL;
}
UTC: 17:30:05 [UTC=UTC, +0000]
Europe/London: 18:30:05 [Europe/London=BST, +0100]
Europe/Madrid: 19:30:05 [Europe/Madrid=CEST, +0200]

As soon as we use named zones acronyms, strange things happen:

foreach (['UTC', 'BST', 'GMT', 'CEST', 'CET'] as $time_zone_id) {
$dt = new DateTime('@1477762205');
$tz = new DateTimeZone($time_zone_id);
$dt->setTimezone($tz);
echo $time_zone_id . ': ' . $dt->format('H:i:s [e=T, O]') . PHP_EOL;
}
UTC: 17:30:05 [UTC=UTC, +0000]
BST: 17:30:05 [BST=BST, +0000]
GMT: 17:30:05 [GMT=GMT, +0000]
CEST: 18:30:05 [CEST=CEST, +0100]
CET: 18:30:05 [CET=CET, +0100]

There's probably some relation with the information (or lack of it) about time zone transitions available in the underlying database:

$dt = new DateTime('@1477762205');
foreach (['UTC', 'BST', 'Europe/London', 'CEST', 'Europe/Madrid'] as $time_zone_id) {
$tz = new DateTimeZone($time_zone_id);
$dt->setTimezone($tz);
echo $time_zone_id . PHP_EOL;
echo '- Time zone offset: ' . $tz->getOffset($dt) . ' seconds' . PHP_EOL;

$transitions = $tz->getTransitions(mktime(0, 0, 0, 1, 1, 2016), mktime(0, 0, 0, 12, 31, 2016));
if ($transitions===false) {
echo '- Error fetching transitions' . PHP_EOL;
} else {
echo '- ' . count($transitions) . ' transitions found' . PHP_EOL;
}
}
UTC
- Time zone offset: 0 seconds
- 1 transitions found
BST
- Time zone offset: 0 seconds
- Error fetching transitions
Europe/London
- Time zone offset: 3600 seconds
- 3 transitions found
CEST
- Time zone offset: 3600 seconds
- Error fetching transitions
Europe/Madrid
- Time zone offset: 7200 seconds
- 3 transitions found

It's really hard to say how much of this is a plain bug and how much is counter-intuitive but documented; the PHP bug database is crowded with not a bug entries which are indeed a misunderstanding but I've personally found weird but actual bugs in date calculations involving DST boundaries.

Relative Date from Unix Timestamp with PHP

There's probably a better way to do it, but here's a rough function I wrote ages ago for this:

function time_ago($datetime)
{
if (is_numeric($datetime)) {
$timestamp = $datetime;
} else {
$timestamp = strtotime($datetime);
}
$diff=time()-$timestamp;

$min=60;
$hour=60*60;
$day=60*60*24;
$month=$day*30;

if($diff<60) //Under a min
{
$timeago = $diff . " seconds";
}elseif ($diff<$hour) //Under an hour
{
$timeago = round($diff/$min) . " mins";
}elseif ($diff<$day) //Under a day
{
$timeago = round($diff/$hour) . " hours";
}elseif ($diff<$month) //Under a day
{
$timeago = round($diff/$day) . " days";
}else
{
$timeago = round($diff/$month) ." months";
}

return $timeago;

}

PHP Function to Calculate Relative Time (Human Readable / Facebook Style)

The problem is that the second array $lengths contains 7 elements so when executing the last iteration of the loop (after deviding by 10 - for the decades) $j = 7, $lengths[7] is undefined, so converted to 0 and therefore the test $difference >= $lengths[$j] returns true. Then the code enters an infinite loop. To overcome this problem, just add one more element to the $lengths array, say "100", so the for loop to terminate after processing the decades. Note that dates can be represented in UNIX timestamp if they are before January 19, 2038. Therefore you cannot calculate dates in more than 4 decates so 100 is sufficiant to break from the loop.

PHP library to generate user friendly relative timestamps

Since there didn't seem to be any library, I've made one myself and got it included in PEAR:

Date_HumanDiff, http://pear.php.net/package/Date_HumanDiff

Code is at http://github.com/pear/Date_HumanDiff

Relative date formatting always outputs 3 hours ago

result of date() depends on your timezone. You can change this behavior by setting timezone manually by date_default_timezone_set()

Microtime to Relative Date Conversion

You may do the following:

$input = 1369057622.4679;

$diff = floor(($input-time())/86400); // calculating the difference

$result = abs($diff) . (abs($diff)==1 ? ' day ':' days ') . ($diff<=0 ? 'ago':'ahead'); // making the result.
echo $result; // output: 1 day ago


Related Topics



Leave a reply



Submit