Skip to content

Instantly share code, notes, and snippets.

@danielgwood
Created April 25, 2011 20:15
Show Gist options
  • Save danielgwood/941126 to your computer and use it in GitHub Desktop.
Save danielgwood/941126 to your computer and use it in GitHub Desktop.
Some utility functions for working with dates in PHP
<?php
class Date
{
/**
* Returns time difference between two timestamps, in human readable format.
*
* @param int $time1 A timestamp.
* @param int $time2 A timestamp, defaults to the current time.
* @param string $output Formatting string specifying which parts of the date to return in the array.
* @return string|array
*/
public static function timespan($time1, $time2 = null, $output = 'years,months,weeks,days,hours,minutes,seconds')
{
// Array with the output formats
$output = preg_split('/[^a-z]+/', strtolower((string) $output));
// Invalid output
if (empty($output)) {
return false;
}
// Make the output values into keys
extract(array_flip($output), EXTR_SKIP);
// Default values
$time1 = max(0, (int) $time1);
$time2 = empty($time2) ? time() : max(0, (int) $time2);
// Calculate timespan (seconds)
$timespan = abs($time1 - $time2);
// All values found using Google Calculator.
// Years and months do not match the formula exactly, due to leap years.
// Years ago, 60 * 60 * 24 * 365
if (isset($years) ) {
$timespan -= 31556926 * ($years = (int) floor($timespan / 31556926));
}
// Months ago, 60 * 60 * 24 * 30
if (isset($months)) {
$timespan -= 2629744 * ($months = (int) floor($timespan / 2629743.83));
}
// Weeks ago, 60 * 60 * 24 * 7
if (isset($weeks)) {
$timespan -= 604800 * ($weeks = (int) floor($timespan / 604800));
}
// Days ago, 60 * 60 * 24
if (isset($days)) {
$timespan -= 86400 * ($days = (int) floor($timespan / 86400));
}
// Hours ago, 60 * 60
if (isset($hours)) {
$timespan -= 3600 * ($hours = (int) floor($timespan / 3600));
}
// Minutes ago, 60
if (isset($minutes)) {
$timespan -= 60 * ($minutes = (int) floor($timespan / 60));
}
// Seconds ago, 1
if (isset($seconds)) {
$seconds = $timespan;
}
// Remove the variables that cannot be accessed
unset($timespan, $time1, $time2);
// Deny access to these variables
$deny = array('deny', 'key', 'difference', 'output');
// Return the difference
$difference = array();
foreach ($output as $key) {
if (isset($$key) AND !in_array($key, $deny)) {
// Add requested key to the output
$difference[$key] = $$key;
}
}
// Invalid output formats string
if (empty($difference)) {
return false;
}
// If only one output format was asked, don't put it in an array
if (count($difference) === 1) {
return current($difference);
}
// Return array
return $difference;
}
/**
* Expands upon the functionality provided by Date::timespan(), such that when provided
* with two timestamps (or one and using time() as the second), it will intelligently
* predict the human readable date format to use, based on the length of the timespan.
* Consequently the time string returned is more of an approximation - it will in some
* cases be less than the length of the actual period, but never more.
*
* timespan < 1 minute: 'X seconds'
* timespan < 1 hour: 'X minutes'
* timespan < 1 day: 'X hours'
* timespan < 1 week: 'X days'
* timespan < 1 month: 'X weeks'
* timespan < 1 year: 'X months'
*
* It will also unpluralise if the unit is 1, so 1 seconds becomes 1 second.
*
* @param int $time1 A timestamp.
* @param int|false $time2 A timestamp, defaults to the current time (passing null). If set to false, the
* first parameter will be treated as the period on its own.
* @return string Human readable format
*/
public static function humanFormat($time1, $time2 = null)
{
// Default values
$time1 = max(0, (int) $time1);
if($time2 !== false) {
$time2 = empty($time2) ? time() : max(0, (int) $time2);
// Calculate timespan (seconds)
$period = abs($time1 - $time2);
} else {
$period = $time1;
}
$format = 'seconds';
if ($period > 31556926) {
// More than one year
$format = 'years';
}
elseif ($period > 2629744) {
// More than one month
$format = 'months';
}
elseif ($period > 604800) {
// More than one week
$format = 'weeks';
}
elseif ($period > 86400) {
// More than one day
$format = 'days';
}
elseif ($period > 3600) {
// More than one hour
$format = 'hours';
}
elseif ($period > 60) {
// More than one minute
$format = 'minutes';
}
if($time2 !== false) {
// Get timespan output
$timespan = self::timespan($time1, $time2, $format);
} else {
$timespan = $time1;
}
// Remove the s
if($timespan == 1) {
$format = substr($format, 0, -1);
}
return $timespan . ' ' . $format;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment