115

I would like to convert a variable $uptime which is seconds, into days, hours, minutes and seconds.

Example:

$uptime = 1640467;

Result should be:

18 days 23 hours 41 minutes
Glavić
  • 42,781
  • 13
  • 77
  • 107
Florian
  • 1,501
  • 3
  • 18
  • 22

30 Answers30

255

This can be achieved with DateTime class

Function:

function secondsToTime($seconds) {
    $dtF = new \DateTime('@0');
    $dtT = new \DateTime("@$seconds");
    return $dtF->diff($dtT)->format('%a days, %h hours, %i minutes and %s seconds');
}

Use:

echo secondsToTime(1640467);
# 18 days, 23 hours, 41 minutes and 7 seconds

demo

Pikamander2
  • 7,332
  • 3
  • 48
  • 69
Glavić
  • 42,781
  • 13
  • 77
  • 107
  • @Glavić How would I add support for week and month to this? – socca1157 Apr 17 '14 at 23:44
  • @socca1157: instead of the used format, use `%y years, %m months, %d days, %i minutes, ...`. If you wish to include weeks, you should calculate it. Example you can see [here](http://stackoverflow.com/a/18602474/67332). – Glavić Apr 18 '14 at 13:27
  • 2
    Be sure to add validation to the function. if (empty($seconds)) { return false;} – a coder Jun 18 '14 at 20:19
  • 6
    @acoder: I think this function should not take care of validation; validation should be setup before function call. Nevertheless, your validation is still wrong, because for example it will also pass alphabet. – Glavić Jul 03 '14 at 08:31
  • Here's the link to the format characters used in this function in case anyone needs it: http://php.net/manual/en/dateinterval.format.php – Mario Awad Nov 11 '15 at 10:11
  • 4
    What does the `@` mean when passed as an argument to the `DateTime` constructor? – Ivanka Todorova Jun 21 '16 at 07:43
  • 5
    @IvankaTodorova: value after `@` is unix timestamp. – Glavić Jun 21 '16 at 17:21
  • 2
    What do `$dtF` and `$dtT` represent here? I think this example could be improved. – Mark Sep 11 '17 at 15:35
  • 1
    @Mark: From and To, but that really doesn't matter in this simple example. – Glavić Sep 11 '17 at 19:36
  • @socca1157 how long is a month? (a: it varies depending on the month) – Thoracius Appotite Jul 20 '19 at 01:11
  • great answer!!! use this for 'years , months, days, hours, minutes and seconds' format $dtF->diff($dtT)->format('%y years, %m months, %d days, %h hours, %i minutes and %s seconds'); – BegYourPardon Jul 06 '21 at 08:21
48

This is the function rewritten to include days. I also changed the variable names to make the code easier to understand...

/** 
 * Convert number of seconds into hours, minutes and seconds 
 * and return an array containing those values 
 * 
 * @param integer $inputSeconds Number of seconds to parse 
 * @return array 
 */ 

function secondsToTime($inputSeconds) {

    $secondsInAMinute = 60;
    $secondsInAnHour  = 60 * $secondsInAMinute;
    $secondsInADay    = 24 * $secondsInAnHour;

    // extract days
    $days = floor($inputSeconds / $secondsInADay);

    // extract hours
    $hourSeconds = $inputSeconds % $secondsInADay;
    $hours = floor($hourSeconds / $secondsInAnHour);

    // extract minutes
    $minuteSeconds = $hourSeconds % $secondsInAnHour;
    $minutes = floor($minuteSeconds / $secondsInAMinute);

    // extract the remaining seconds
    $remainingSeconds = $minuteSeconds % $secondsInAMinute;
    $seconds = ceil($remainingSeconds);

    // return the final array
    $obj = array(
        'd' => (int) $days,
        'h' => (int) $hours,
        'm' => (int) $minutes,
        's' => (int) $seconds,
    );
    return $obj;
}

Source: CodeAid() - http://codeaid.net/php/convert-seconds-to-hours-minutes-and-seconds-(php)

Matthew
  • 28,056
  • 26
  • 104
  • 170
Julian Moreno
  • 1,084
  • 3
  • 15
  • 30
  • It would be nice to include source – Martin. Nov 25 '11 at 20:19
  • would you be kind enough to add days to this function? – knittledan Apr 13 '12 at 23:50
  • @knittledan, doesnt appear so :) – AO_ May 01 '12 at 12:25
  • 1
    @hsmoore.com I went ahead and figured this out $days = floor($seconds / (60 * 60 * 24)); // extract hours $divisor_for_hours = $seconds % (60 * 60 * 24); $hours = floor( $divisor_for_hours / (60 * 60)); – knittledan May 01 '12 at 18:20
  • 1
    This doesn't work as expected for days. You need to subtract ($days * 24) from $hours, or else the hours in the days will be double counted in $days and $hours. e.g. input 100000 => 1 day and 27 hours. This should be 1 day and 3 hours. – finiteloop Oct 20 '14 at 19:58
  • Also, this doesn't work for summer/winter time countries. – niconoe Oct 26 '15 at 12:47
43

Based on the answer by Julian Moreno, but changed to give the response as a string (not an array), only include the time intervals required and not assume the plural.

The difference between this and the highest voted answer is:

For 259264 seconds, this code would give

3 days, 1 minute, 4 seconds

For 259264 seconds, the highest voted answer (by Glavić) would give

3 days, 0 hours, 1 minutes and 4 seconds

function secondsToTime($inputSeconds) {
    $secondsInAMinute = 60;
    $secondsInAnHour = 60 * $secondsInAMinute;
    $secondsInADay = 24 * $secondsInAnHour;

    // Extract days
    $days = floor($inputSeconds / $secondsInADay);

    // Extract hours
    $hourSeconds = $inputSeconds % $secondsInADay;
    $hours = floor($hourSeconds / $secondsInAnHour);

    // Extract minutes
    $minuteSeconds = $hourSeconds % $secondsInAnHour;
    $minutes = floor($minuteSeconds / $secondsInAMinute);

    // Extract the remaining seconds
    $remainingSeconds = $minuteSeconds % $secondsInAMinute;
    $seconds = ceil($remainingSeconds);

    // Format and return
    $timeParts = [];
    $sections = [
        'day' => (int)$days,
        'hour' => (int)$hours,
        'minute' => (int)$minutes,
        'second' => (int)$seconds,
    ];

    foreach ($sections as $name => $value){
        if ($value > 0){
            $timeParts[] = $value. ' '.$name.($value == 1 ? '' : 's');
        }
    }

    return implode(', ', $timeParts);
}

I hope this helps someone.

Luke Cousins
  • 2,068
  • 1
  • 20
  • 38
  • 2
    I prefer this one because it removes the "s", from "1 hours", and, in my case, I wanted to remove days and just have a large hour count, and this method was very easy to adapt to that <3. – Ryan S May 24 '17 at 14:42
  • 1
    Very nice Luke, keeping it compact and clean! – VoidZA Jan 18 '20 at 18:12
29

Here it is a simple 8-lines PHP function that converts a number of seconds into a human readable string including number of months for large amounts of seconds:

PHP function seconds2human()

function seconds2human($ss) {
$s = $ss%60;
$m = floor(($ss%3600)/60);
$h = floor(($ss%86400)/3600);
$d = floor(($ss%2592000)/86400);
$M = floor($ss/2592000);

return "$M months, $d days, $h hours, $m minutes, $s seconds";
}
Community
  • 1
  • 1
snippetsofcode
  • 937
  • 2
  • 10
  • 10
15
gmdate("d H:i:s",1640467);

Result will be 19 23:41:07. Even if the time is an extra 1 second, it causes the day to change. So it turns out 19. You can explode the result for your needs and fix this.

Caner SAYGIN
  • 527
  • 3
  • 11
  • You can also improve this code like this:`$uptime = gmdate("y m d H:i:s", 1640467); $uptimeDetail = explode(" ",$uptime); echo (string)($uptimeDetail[0]-70).' year(s) '.(string)($uptimeDetail[1]-1).' month(s) '.(string)($uptimeDetail[2]-1).' day(s) '.(string)$uptimeDetail[3];` This will also give you year and month informations too. – Caner SAYGIN Oct 16 '14 at 21:40
  • 1
    To prevent the +1 day error simply substract (24*60*60) from the source timestamp in seconds. – andreszs Feb 26 '20 at 19:40
  • `Uncaught ReferenceError: gmdate is not defined` – Nabi K.A.Z. Apr 07 '22 at 19:02
  • You should check here: https://www.php.net/manual/en/function.gmdate.php Good luck – Caner SAYGIN Jun 05 '22 at 15:49
14

There are some very good answers here but none of them covered my needs. I built on Glavic's answer to add some extra features that I needed;

  • Don't print zeros. So "5 minutes" instead of " 0 hours, 5 minutes"
  • Handle plural properly instead of defaulting to the plural form.
  • Limit the output to a set number of units; So "2 months, 2 days" instead of "2 months, 2 days, 1 hour, 45 minutes"

You can see a running version of the code here.

function secondsToHumanReadable(int $seconds, int $requiredParts = null)
{
    $from     = new \DateTime('@0');
    $to       = new \DateTime("@$seconds");
    $interval = $from->diff($to);
    $str      = '';

    $parts = [
        'y' => 'year',
        'm' => 'month',
        'd' => 'day',
        'h' => 'hour',
        'i' => 'minute',
        's' => 'second',
    ];

    $includedParts = 0;

    foreach ($parts as $key => $text) {
        if ($requiredParts && $includedParts >= $requiredParts) {
            break;
        }

        $currentPart = $interval->{$key};

        if (empty($currentPart)) {
            continue;
        }

        if (!empty($str)) {
            $str .= ', ';
        }

        $str .= sprintf('%d %s', $currentPart, $text);

        if ($currentPart > 1) {
            // handle plural
            $str .= 's';
        }

        $includedParts++;
    }

    return $str;
}
Ramy Nasr
  • 2,367
  • 20
  • 24
11

Short, simple, reliable :

function secondsToDHMS($seconds) {
    $s = (int)$seconds;
    return sprintf('%d:%02d:%02d:%02d', $s/86400, $s/3600%24, $s/60%60, $s%60);
}
  • 3
    Further explanation would go a long ways in this answer, such as what the integer constants represent and how string formatting works with sprintf. –  Jun 19 '17 at 23:12
  • 1
    I would do sprintf('%dd:%02dh:%02dm:%02ds', $s/86400, $s/3600%24, $s/60%60, $s%60); just to be even more humnan (ex: 0d:00h:05m:00s). But probably the best solution here. – Ricardo Martins Aug 29 '19 at 01:42
  • When you have days, it begins to look ... interesting: 14:22:13:18; Fourteen days. – Jeffz May 02 '21 at 10:48
9

Laravel example

700+ locales support by Carbon

\Carbon\CarbonInterval::seconds(1640467)->cascade()->forHumans(); //2 weeks 4 days 23 hours 41 minutes 7 seconds
the_hasanov
  • 782
  • 7
  • 15
8

The simplest approach would be to create a method that returns a DateInterval from the DateTime::diff of the relative time in $seconds from the current time $now which you can then chain and format. For example:-

public function toDateInterval($seconds) {
    return date_create('@' . (($now = time()) + $seconds))->diff(date_create('@' . $now));
}

Now chain your method call to DateInterval::format

echo $this->toDateInterval(1640467)->format('%a days %h hours %i minutes'));

Result:

18 days 23 hours 41 minutes
Trent Renshaw
  • 512
  • 7
  • 14
4
function convert($seconds){
$string = "";

$days = intval(intval($seconds) / (3600*24));
$hours = (intval($seconds) / 3600) % 24;
$minutes = (intval($seconds) / 60) % 60;
$seconds = (intval($seconds)) % 60;

if($days> 0){
    $string .= "$days days ";
}
if($hours > 0){
    $string .= "$hours hours ";
}
if($minutes > 0){
    $string .= "$minutes minutes ";
}
if ($seconds > 0){
    $string .= "$seconds seconds";
}

return $string;
}

echo convert(3744000);
3

Although it is quite old question - one may find these useful (not written to be fast):

function d_h_m_s__string1($seconds)
{
    $ret = '';
    $divs = array(86400, 3600, 60, 1);

    for ($d = 0; $d < 4; $d++)
    {
        $q = (int)($seconds / $divs[$d]);
        $r = $seconds % $divs[$d];
        $ret .= sprintf("%d%s", $q, substr('dhms', $d, 1));
        $seconds = $r;
    }

    return $ret;
}

function d_h_m_s__string2($seconds)
{
    if ($seconds == 0) return '0s';

    $can_print = false; // to skip 0d, 0d0m ....
    $ret = '';
    $divs = array(86400, 3600, 60, 1);

    for ($d = 0; $d < 4; $d++)
    {
        $q = (int)($seconds / $divs[$d]);
        $r = $seconds % $divs[$d];
        if ($q != 0) $can_print = true;
        if ($can_print) $ret .= sprintf("%d%s", $q, substr('dhms', $d, 1));
        $seconds = $r;
    }

    return $ret;
}

function d_h_m_s__array($seconds)
{
    $ret = array();

    $divs = array(86400, 3600, 60, 1);

    for ($d = 0; $d < 4; $d++)
    {
        $q = $seconds / $divs[$d];
        $r = $seconds % $divs[$d];
        $ret[substr('dhms', $d, 1)] = $q;

        $seconds = $r;
    }

    return $ret;
}

echo d_h_m_s__string1(0*86400+21*3600+57*60+13) . "\n";
echo d_h_m_s__string2(0*86400+21*3600+57*60+13) . "\n";

$ret = d_h_m_s__array(9*86400+21*3600+57*60+13);
printf("%dd%dh%dm%ds\n", $ret['d'], $ret['h'], $ret['m'], $ret['s']);

result:

0d21h57m13s
21h57m13s
9d21h57m13s
Artur
  • 7,038
  • 2
  • 25
  • 39
3
function seconds_to_time($seconds){
     // extract hours
    $hours = floor($seconds / (60 * 60));

    // extract minutes
    $divisor_for_minutes = $seconds % (60 * 60);
    $minutes = floor($divisor_for_minutes / 60);

    // extract the remaining seconds
    $divisor_for_seconds = $divisor_for_minutes % 60;
    $seconds = ceil($divisor_for_seconds);

    //create string HH:MM:SS
    $ret = $hours.":".$minutes.":".$seconds;
    return($ret);
}
James Doherty
  • 1,271
  • 1
  • 8
  • 6
3

Solution that should exclude 0 values and set correct singular/plural values

use DateInterval;
use DateTime;

class TimeIntervalFormatter
{

    public static function fromSeconds($seconds)
    {
        $seconds = (int)$seconds;
        $dateTime = new DateTime();
        $dateTime->sub(new DateInterval("PT{$seconds}S"));
        $interval = (new DateTime())->diff($dateTime);
        $pieces = explode(' ', $interval->format('%y %m %d %h %i %s'));
        $intervals = ['year', 'month', 'day', 'hour', 'minute', 'second'];
        $result = [];
        foreach ($pieces as $i => $value) {
            if (!$value) {
                continue;
            }
            $periodName = $intervals[$i];
            if ($value > 1) {
                $periodName .= 's';
            }
            $result[] = "{$value} {$periodName}";
        }
        return implode(', ', $result);
    }
}
radzserg
  • 1,258
  • 1
  • 13
  • 22
3

I don't know why some of these answers are ridiculously long or complex. Here's one using the DateTime Class. Kind of similar to radzserg's answer. This will only display the units necessary, and negative times will have the 'ago' suffix...

function calctime($seconds = 0) {

    $datetime1 = date_create("@0");
    $datetime2 = date_create("@$seconds");
    $interval = date_diff($datetime1, $datetime2);

    if ( $interval->y >= 1 ) $thetime[] = pluralize( $interval->y, 'year' );
    if ( $interval->m >= 1 ) $thetime[] = pluralize( $interval->m, 'month' );
    if ( $interval->d >= 1 ) $thetime[] = pluralize( $interval->d, 'day' );
    if ( $interval->h >= 1 ) $thetime[] = pluralize( $interval->h, 'hour' );
    if ( $interval->i >= 1 ) $thetime[] = pluralize( $interval->i, 'minute' );
    if ( $interval->s >= 1 ) $thetime[] = pluralize( $interval->s, 'second' );

    return isset($thetime) ? implode(' ', $thetime) . ($interval->invert ? ' ago' : '') : NULL;
}

function pluralize($count, $text) {
    return $count . ($count == 1 ? " $text" : " ${text}s");
}

// Examples:
//    -86400 = 1 day ago
//     12345 = 3 hours 25 minutes 45 seconds
// 987654321 = 31 years 3 months 18 days 4 hours 25 minutes 21 seconds

EDIT: If you want to condense the above example down to use less variables / space (at the expense of legibility), here is an alternate version that does the same thing:

function calctime($seconds = 0) {
    $interval = date_diff(date_create("@0"),date_create("@$seconds"));

    foreach (array('y'=>'year','m'=>'month','d'=>'day','h'=>'hour','i'=>'minute','s'=>'second') as $format=>$desc) {
        if ($interval->$format >= 1) $thetime[] = $interval->$format . ($interval->$format == 1 ? " $desc" : " {$desc}s");
    }

    return isset($thetime) ? implode(' ', $thetime) . ($interval->invert ? ' ago' : '') : NULL;
}
Jason
  • 83
  • 1
  • 6
  • You might want to add safety to the calctime function to protect against 0 seconds. The current code throws an error. Wrap `$thetime` in the return, e.g., `isset($thetime)` – Stargazing Worm Aug 20 '20 at 17:00
  • Thanks for the suggestion, you are correct about the error (I can't believe I missed that). I've updated the code accordingly! – Jason Aug 25 '20 at 22:49
2

an extended version of Glavić's excellent solution , having integer validation, solving the 1 s problem, and additional support for years and months, at the expense of being less computer parsing friendly in favor of being more human friendly:

<?php
function secondsToHumanReadable(/*int*/ $seconds)/*: string*/ {
    //if you dont need php5 support, just remove the is_int check and make the input argument type int.
    if(!\is_int($seconds)){
        throw new \InvalidArgumentException('Argument 1 passed to secondsToHumanReadable() must be of the type int, '.\gettype($seconds).' given');
    }
    $dtF = new \DateTime ( '@0' );
    $dtT = new \DateTime ( "@$seconds" );
    $ret = '';
    if ($seconds === 0) {
        // special case
        return '0 seconds';
    }
    $diff = $dtF->diff ( $dtT );
    foreach ( array (
            'y' => 'year',
            'm' => 'month',
            'd' => 'day',
            'h' => 'hour',
            'i' => 'minute',
            's' => 'second' 
    ) as $time => $timename ) {
        if ($diff->$time !== 0) {
            $ret .= $diff->$time . ' ' . $timename;
            if ($diff->$time !== 1 && $diff->$time !== -1 ) {
                $ret .= 's';
            }
            $ret .= ' ';
        }
    }
    return substr ( $ret, 0, - 1 );
}

var_dump(secondsToHumanReadable(1*60*60*2+1)); -> string(16) "2 hours 1 second"

Community
  • 1
  • 1
hanshenrik
  • 19,904
  • 4
  • 43
  • 89
2
function secondsToTime($seconds) {
    $time = [];
    $minutes = $seconds / 60;
    $seconds = $seconds % 60;
    $hours = $minutes / 60;
    $minutes = $minutes % 60;
    $days = $hours / 24;
    $hours = $hours % 24;
    $month = $days /30;
    $days = $days % 30;
    $year = $month / 12;
    $month = $month % 12;
    if ((int)($year) != 0){
        array_push($time,[ "year" => (int)($year)]);
    }
    if ($month != 0){
        array_push($time, ["months" => $month]);
    }
    if ($days != 0){
        array_push($time,["days" => $days]);
    }
    if ($hours != 0){
        array_push($time,["hours" => $hours]);
    }
    if ($minutes != 0){
        array_push($time,["minutes" => $minutes]);
    }
    if ($seconds != 0){
        array_push($time,["seconds" => $seconds]);
    }
    return $time;
}
  • Your answer could be improved with additional supporting information. Please [edit] to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers [in the help center](/help/how-to-answer). – Community Oct 18 '21 at 10:53
2

I think Carbon will give you all variety that you want

so for your example you will add this code

$seconds = 1640467;
$time = Carbon::now();
$humanTime = $time->diffForHumans($time->copy()->addSeconds($seconds), true, false, 4);

the output will be like this

2 weeks 4 days 23 hours 41 minutes

Ahmed Bermawy
  • 2,290
  • 4
  • 35
  • 42
1

All in one solution. Gives no units with zeroes. Will only produce number of units you specify (3 by default). Quite long, perhaps not very elegant. Defines are optional, but might come in handy in a big project.

define('OneMonth', 2592000);
define('OneWeek', 604800);  
define('OneDay', 86400);
define('OneHour', 3600);    
define('OneMinute', 60);

function SecondsToTime($seconds, $num_units=3) {        
    $time_descr = array(
                "months" => floor($seconds / OneMonth),
                "weeks" => floor(($seconds%OneMonth) / OneWeek),
                "days" => floor(($seconds%OneWeek) / OneDay),
                "hours" => floor(($seconds%OneDay) / OneHour),
                "mins" => floor(($seconds%OneHour) / OneMinute),
                "secs" => floor($seconds%OneMinute),
                );  
        
    $res = "";
    $counter = 0;
    
    foreach ($time_descr as $k => $v) {
        if ($v) {
            $res.=$v." ".$k;
            $counter++;
            if($counter>=$num_units)
                break;
            elseif($counter)
                $res.=", ";             
        }
    }   
    return $res;
}
miken32
  • 42,008
  • 16
  • 111
  • 154
AnDenix
  • 21
  • 3
1

Interval class I have written can be used. It can be used in opposite way too.

composer require lubos/cakephp-interval

$Interval = new \Interval\Interval\Interval();

// output 2w 6h
echo $Interval->toHuman((2 * 5 * 8 + 6) * 3600);

// output 36000
echo $Interval->toSeconds('1d 2h');

More info here https://github.com/LubosRemplik/CakePHP-Interval

Luboš Remplík
  • 526
  • 5
  • 10
1

With DateInterval :

$d1 = new DateTime();
$d2 = new DateTime();
$d2->add(new DateInterval('PT'.$timespan.'S'));

$interval = $d2->diff($d1);
echo $interval->format('%a days, %h hours, %i minutes and %s seconds');

// Or
echo sprintf('%d days, %d hours, %d minutes and %d seconds',
    $interval->days,
    $interval->h,
    $interval->i,
    $interval->s
);

// $interval->y => years
// $interval->m => months
// $interval->d => days
// $interval->h => hours
// $interval->i => minutes
// $interval->s => seconds
// $interval->days => total number of days
Andrew Schultz
  • 4,092
  • 2
  • 21
  • 44
Zayon
  • 11
  • 2
1

A bit more elaborated, skipping the time units which are zero

function secondsToTime($ss) 
{
    $htmlOut="";
    $s = $ss%60;
    $m = floor(($ss%3600)/60);
    $h = floor(($ss%86400)/3600);
    $d = floor(($ss%2592000)/86400);
    $M = floor($ss/2592000);
    if ( $M > 0 )
    {
        $htmlOut.="$M months";      
    }
    if ( $d > 0 )
    {
        if ( $M > 0 )
         $htmlOut.=", ";
        $htmlOut.="$d days";        
    }
    if ( $h > 0 )
    {
        if ( $d > 0 )
         $htmlOut.=", ";
        $htmlOut.="$h hours";       
    }
    if ( $m > 0 )
    {
        if ( $h > 0 )
         $htmlOut.=", ";            
        $htmlOut.="$m minutes";     
    }
    if ( $s > 0 )
    {
        if ( $m > 0 )
         $htmlOut.=" and ";         
        $htmlOut.="$s seconds";     
    }       
    return $htmlOut;
}   
Daniel J.
  • 308
  • 2
  • 12
0

Here's some code that I like to use for the purpose of getting the duration between two dates. It accepts two dates and gives you a nice sentence structured reply.

This is a slightly modified version of the code found here.

<?php

function dateDiff($time1, $time2, $precision = 6, $offset = false) {

    // If not numeric then convert texts to unix timestamps

    if (!is_int($time1)) {
            $time1 = strtotime($time1);
    }

    if (!is_int($time2)) {
            if (!$offset) {
                    $time2 = strtotime($time2);
            }
            else {
                    $time2 = strtotime($time2) - $offset;
            }
    }

    // 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) {

            // Create temp time from time1 and interval

            $ttime = strtotime('+1 ' . $interval, $time1);

            // Set initial values

            $add = 1;
            $looped = 0;

            // Loop until temp time is smaller than time2

            while ($time2 >= $ttime) {

                    // Create new temp time from time1 and interval

                    $add++;
                    $ttime = strtotime("+" . $add . " " . $interval, $time1);
                    $looped++;
            }

            $time1 = strtotime("+" . $looped . " " . $interval, $time1);
            $diffs[$interval] = $looped;
    }

    $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++;
            }
    }

    if (!empty($times)) {

            // Return string with times

            return implode(", ", $times);
    }
    else {

            // Return 0 Seconds

    }

    return '0 Seconds';
}

Source: https://gist.github.com/ozh/8169202

0

The solution for this one I used (back to the days while learning PHP) without any in-functions:

$days = (int)($uptime/86400); //1day = 86400seconds
$rdays = (uptime-($days*86400)); 
//seconds remaining after uptime was converted into days
$hours = (int)($rdays/3600);//1hour = 3600seconds,converting remaining seconds into hours
$rhours = ($rdays-($hours*3600));
//seconds remaining after $rdays was converted into hours
$minutes = (int)($rhours/60); // 1minute = 60seconds, converting remaining seconds into minutes
echo "$days:$hours:$minutes";

Though this was an old question, new learners who come across this, may find this answer useful.

0
a=int(input("Enter your number by seconds "))
d=a//(24*3600)   #Days
h=a//(60*60)%24  #hours
m=a//60%60       #minutes
s=a%60           #seconds
print("Days ",d,"hours ",h,"minutes ",m,"seconds ",s)
0

I am editing one of the code to work it well when negative value comes. floor() function is not giving the correct count when the value is negative. So we need to use abs() function before using it in the floor() function. $inputSeconds variable can be the difference between the current time stamp and the required date.

/** 
 * Convert number of seconds into hours, minutes and seconds 
 * and return an array containing those values 
 * 
 * @param integer $inputSeconds Number of seconds to parse 
 * @return array 
 */ 

function secondsToTime($inputSeconds) {

    $secondsInAMinute = 60;
    $secondsInAnHour  = 60 * $secondsInAMinute;
    $secondsInADay    = 24 * $secondsInAnHour;

    // extract days
    $days = abs($inputSeconds / $secondsInADay);
    $days = floor($days);

    // extract hours
    $hourSeconds = $inputSeconds % $secondsInADay;
    $hours = abs($hourSeconds / $secondsInAnHour);
    $hours = floor($hours);

    // extract minutes
    $minuteSeconds = $hourSeconds % $secondsInAnHour;
    $minutes = abs($minuteSeconds / $secondsInAMinute);
    $minutes = floor($minutes);

    // extract the remaining seconds
    $remainingSeconds = $minuteSeconds % $secondsInAMinute;
    $seconds = abs($remainingSeconds);
    $seconds = ceil($remainingSeconds);

    // return the final array
    $obj = array(
        'd' => (int) $days,
        'h' => (int) $hours,
        'm' => (int) $minutes,
        's' => (int) $seconds,
    );
    return $obj;
}
0

A variation on @Glavić's answer - this one hides leading zeros for shorter results and uses plurals in correct places. It also removes unnecessary precision (e.g. if the time difference is over 2 hours, you probably don't care how many minutes or seconds).

function secondsToTime($seconds)
{
    $dtF = new \DateTime('@0');
    $dtT = new \DateTime("@$seconds");
    $dateInterval = $dtF->diff($dtT);
    $days_t = 'day';
    $hours_t = 'hour';
    $minutes_t = 'minute';
    $seconds_t = 'second';
    if ((int)$dateInterval->d > 1) {
        $days_t = 'days';
    }
    if ((int)$dateInterval->h > 1) {
        $hours_t = 'hours';
    }
    if ((int)$dateInterval->i > 1) {
        $minutes_t = 'minutes';
    }
    if ((int)$dateInterval->s > 1) {
        $seconds_t = 'seconds';
    }


    if ((int)$dateInterval->d > 0) {
        if ((int)$dateInterval->d > 1 || (int)$dateInterval->h === 0) {
            return $dateInterval->format("%a $days_t");
        } else {
            return $dateInterval->format("%a $days_t, %h $hours_t");
        }
    } else if ((int)$dateInterval->h > 0) {
        if ((int)$dateInterval->h > 1 || (int)$dateInterval->i === 0) {
            return $dateInterval->format("%h $hours_t");
        } else {
            return $dateInterval->format("%h $hours_t, %i $minutes_t");
        }
    } else if ((int)$dateInterval->i > 0) {
        if ((int)$dateInterval->i > 1 || (int)$dateInterval->s === 0) {
            return $dateInterval->format("%i $minutes_t");
        } else {
            return $dateInterval->format("%i $minutes_t, %s $seconds_t");
        }
    } else {
        return $dateInterval->format("%s $seconds_t");
    }

}
php > echo secondsToTime(60);
1 minute
php > echo secondsToTime(61);
1 minute, 1 second
php > echo secondsToTime(120);
2 minutes
php > echo secondsToTime(121);
2 minutes
php > echo secondsToTime(2000);
33 minutes
php > echo secondsToTime(4000);
1 hour, 6 minutes
php > echo secondsToTime(4001);
1 hour, 6 minutes
php > echo secondsToTime(40001);
11 hours
php > echo secondsToTime(400000);
4 days
Mike Furlender
  • 3,869
  • 5
  • 47
  • 75
0

Added some formatting modified from Glavić's great answer for Facebook style time of post count up....

        function secondsToTime($seconds) {
    $dtF = new \DateTime('@0');
    $dtT = new \DateTime("@$seconds");

    switch($seconds){
        case ($seconds<60*60*24): // if time is less than one day
        return $dtF->diff($dtT)->format('%h hours, %i minutes, %s seconds');
        break;
        case ($seconds<60*60*24*31 && $seconds>60*60*24): // if time is between 1 day and 1 month
        return $dtF->diff($dtT)->format('%d days, %h hours');
        break;
        case ($seconds<60*60*24*365 && $seconds>60*60*24*31): // if time between 1 month and 1 year
        return $dtF->diff($dtT)->format('%m months, %d days');
        break;
        case ($seconds>60*60*24*365): // if time is longer than 1 year
        return $dtF->diff($dtT)->format('%y years, %m months');
        break;


    }
0
function secondsToHumanTime(int $seconds, array $filter = []): string
{
    $intervalDefinitions = [
       'year'   => ['interval' => 31536000, 'labels' => ['year', 'years']],
       'month'  => ['interval' => 2592000, 'labels' => ['month', 'months']],
       'week'   => ['interval' => 604800, 'labels' => ['week', 'weeks']],
       'day'    => ['interval' => 86400, 'labels' => ['day', 'days']],
       'hour'   => ['interval' => 3600, 'labels' => ['hour', 'hours']],
       'minute' => ['interval' => 60, 'labels' => ['minute','minutes']],
       'second' => ['interval' => 1, 'labels' => ['second','seconds']],
    ];

    $filteredIntervalDefinitions = array_column(
        $filter ?
            array_intersect_key($intervalDefinitions, array_flip($filter)) :
            $intervalDefinitions,
        'labels',
        'interval'
    );

    $intervals = [];
    foreach ($filteredIntervalDefinitions as $numerator => $labels) {
        if($counter = intdiv($seconds, $numerator)) {
            $intervals[] = $counter . ' ' . ($labels[(int)((bool)($counter - 1))] ?? '');
            $seconds -= ($counter * $numerator);
        }
    }

    return implode(' ', $intervals);
}

Examples:

echo secondsToHumanTime(0) ."\n";
echo secondsToHumanTime(10) ."\n";
echo secondsToHumanTime(100)."\n";
echo secondsToHumanTime(1000)."\n";
echo secondsToHumanTime(10000)."\n";
echo secondsToHumanTime(100000)."\n";
echo secondsToHumanTime(1000000)."\n";
echo secondsToHumanTime(10000000)."\n";
echo secondsToHumanTime(100000000)."\n";
echo secondsToHumanTime(1000000000)."\n";
echo secondsToHumanTime(10000000000)."\n";
echo secondsToHumanTime(100000000000)."\n";

Results:

10 seconds
1 minute 40 seconds
16 minutes 40 seconds
2 hours 46 minutes 40 seconds
1 day 3 hours 46 minutes 40 seconds
1 week 4 days 13 hours 46 minutes 40 seconds
3 months 3 weeks 4 days 17 hours 46 minutes 40 seconds
3 years 2 months 2 days 9 hours 46 minutes 40 seconds
31 years 8 months 2 weeks 5 days 1 hour 46 minutes 40 seconds
317 years 1 month 5 days 17 hours 46 minutes 40 seconds
3170 years 11 months 3 weeks 6 days 9 hours 46 minutes 40 seconds

Examples with filter:

echo secondsToHumanTime(100000000)."\n";

//only years and months
echo secondsToHumanTime(100000000, ['year', 'month'])."\n";

//only years and days
echo secondsToHumanTime(100000000, ['year','day'])."\n";

//...
echo secondsToHumanTime(100000000 - 39, ['year', 'minute', 'second'])."\n";

Results:

3 years 2 months 2 days 9 hours 46 minutes 40 seconds
3 years 2 months
3 years 62 days
3 years 89866 minutes 1 second

-1
foreach ($email as $temp => $value) {
    $dat = strtotime($value['subscription_expiration']); //$value come from mysql database
//$email is an array from mysqli_query()
    $date = strtotime(date('Y-m-d'));

    $_SESSION['expiry'] = (((($dat - $date)/60)/60)/24)." Days Left";
//you will get the difference from current date in days.
}

$value come from Database. This code is in Codeigniter. $SESSION is used for storing user subscriptions. it is mandatory. I used it in my case, you can use whatever you want.

Tayyab Hayat
  • 815
  • 1
  • 9
  • 22
-2

This is a function i used in the past for substracting a date from another one related with your question, my principe was to get how many days, hours minutes and seconds has left until a product has expired :

$expirationDate = strtotime("2015-01-12 20:08:23");
$toDay = strtotime(date('Y-m-d H:i:s'));
$difference = abs($toDay - $expirationDate);
$days = floor($difference / 86400);
$hours = floor(($difference - $days * 86400) / 3600);
$minutes = floor(($difference - $days * 86400 - $hours * 3600) / 60);
$seconds = floor($difference - $days * 86400 - $hours * 3600 - $minutes * 60);

echo "{$days} days {$hours} hours {$minutes} minutes {$seconds} seconds";
Krazii KiiD
  • 123
  • 1
  • 2
  • 10