Conversión de marca de tiempo a tiempo atrás en PHP, por ejemplo, hace 1 día, hace 2 días ...


234

Estoy tratando de convertir una marca de tiempo del formato 2009-09-12 20:57:19y convertirlo en algo así como 3 minutes agocon PHP.

Encontré un script útil para hacer esto, pero creo que está buscando un formato diferente para usar como variable de tiempo. El script que quiero modificar para trabajar con este formato es:

function _ago($tm,$rcs = 0) {
    $cur_tm = time(); 
    $dif = $cur_tm-$tm;
    $pds = array('second','minute','hour','day','week','month','year','decade');
    $lngh = array(1,60,3600,86400,604800,2630880,31570560,315705600);

    for($v = sizeof($lngh)-1; ($v >= 0)&&(($no = $dif/$lngh[$v])<=1); $v--); if($v < 0) $v = 0; $_tm = $cur_tm-($dif%$lngh[$v]);
        $no = floor($no);
        if($no <> 1)
            $pds[$v] .='s';
        $x = sprintf("%d %s ",$no,$pds[$v]);
        if(($rcs == 1)&&($v >= 1)&&(($cur_tm-$_tm) > 0))
            $x .= time_ago($_tm);
        return $x;
    }

Creo que en esas primeras líneas el script está tratando de hacer algo que se parece a esto (matemática de formato de fecha diferente):

$dif = 1252809479 - 2009-09-12 20:57:19;

¿Cómo haría para convertir mi marca de tiempo en ese formato (unix?)?



Respuestas:


451

Use ejemplo:

echo time_elapsed_string('2013-05-01 00:22:35');
echo time_elapsed_string('@1367367755'); # timestamp input
echo time_elapsed_string('2013-05-01 00:22:35', true);

La entrada puede ser cualquier formato de fecha y hora admitido .

Salida:

4 months ago
4 months ago
4 months, 2 weeks, 3 days, 1 hour, 49 minutes, 15 seconds ago

Función:

function time_elapsed_string($datetime, $full = false) {
    $now = new DateTime;
    $ago = new DateTime($datetime);
    $diff = $now->diff($ago);

    $diff->w = floor($diff->d / 7);
    $diff->d -= $diff->w * 7;

    $string = array(
        'y' => 'year',
        'm' => 'month',
        'w' => 'week',
        'd' => 'day',
        'h' => 'hour',
        'i' => 'minute',
        's' => 'second',
    );
    foreach ($string as $k => &$v) {
        if ($diff->$k) {
            $v = $diff->$k . ' ' . $v . ($diff->$k > 1 ? 's' : '');
        } else {
            unset($string[$k]);
        }
    }

    if (!$full) $string = array_slice($string, 0, 1);
    return $string ? implode(', ', $string) . ' ago' : 'just now';
}

2
La parte de la semana es agradable, pero en general la función debería ser más flexible ( $fulldebería ser una entrada de cadena para filtrar la salida según sea necesario). por ej time_elapsed_string($datetime, $format = "ymw"). Versión plana de PS: stackoverflow.com/a/5010169/318765
mgutt

15
En cuanto a mi último comentario: Cambiar $full = falsea $level = 7y if (!$full) $string = array_slice($string, 0, 1);a $string = array_slice($string, 0, $level);y llamada time_elapsed_string($datetime, 2)para obtener sólo las dos cadenas de fecha más altos. Creo que esto debería satisfacer todas las necesidades.
mgutt

1
@mgutt: ofc esta función no funcionará para cualquier escenario de caso de usuario; pero es un buen punto de partida, donde puedes, con una solución mínima, obtener lo que necesitas, como ya lo has demostrado ...
Glavić

1
Estoy llegando Unknown property (w)a esta línea$diff->w = floor($diff->d / 7);
vonUbisch

2
Para solucionar este problema Unknown property (w)en PHP5.3 y versiones posteriores, convierta $ diff de un objeto en una matriz y ajuste el resto del código en consecuencia. Tengo la solución publicada aquí: stackoverflow.com/a/32723846/235633
bafromca

104
function time_elapsed_string($ptime)
{
    $etime = time() - $ptime;

    if ($etime < 1)
    {
        return '0 seconds';
    }

    $a = array( 365 * 24 * 60 * 60  =>  'year',
                 30 * 24 * 60 * 60  =>  'month',
                      24 * 60 * 60  =>  'day',
                           60 * 60  =>  'hour',
                                60  =>  'minute',
                                 1  =>  'second'
                );
    $a_plural = array( 'year'   => 'years',
                       'month'  => 'months',
                       'day'    => 'days',
                       'hour'   => 'hours',
                       'minute' => 'minutes',
                       'second' => 'seconds'
                );

    foreach ($a as $secs => $str)
    {
        $d = $etime / $secs;
        if ($d >= 1)
        {
            $r = round($d);
            return $r . ' ' . ($r > 1 ? $a_plural[$str] : $str) . ' ago';
        }
    }
}

73
Esta no es una buena solución, ya que está usando 30days for month, y 12x30days for year, y por eso devolverá un número inválido de años debajo del año <= 1978. Ejemplo donde devuelve 39 años, pero debería 38. Y tampoco funciona para años debajo de 1970.
Glavić

45
Pésima solución. ¿Por qué esto tiene 42 votos a favor y la respuesta seleccionada? ¿Desde cuándo cada mes tiene 30 días?
BadHorsie

55
@wassimboy, ¿podrías decirme por qué quieres rechazar mi respuesta? Si mi respuesta no es lo suficientemente buena, puede escribir un comentario para corregirlo sin un voto negativo.
Ayman Hussein

8
Su respuesta no es buena porque cuenta 30 días por mes y no todos los meses tienen 30 días. Lea los otros comentarios anteriores.
Tomás González el

12
Esta es una función para devolver una frase general, como "¿aproximadamente hace cuánto tiempo se hizo este comentario"? No es preciso y tiene algunas desventajas, como se mencionó anteriormente, pero para las fechas en el pasado cercano (digamos 30 años y menos) nos da a los humanos no precisos una idea de cuánto tiempo hace que ocurrió un evento. Funcionó bien para mi aplicación.
Tim Dearborn

29
$time_elapsed = timeAgo($time_ago); //The argument $time_ago is in timestamp (Y-m-d H:i:s)format.

//Function definition

function timeAgo($time_ago)
{
    $time_ago = strtotime($time_ago);
    $cur_time   = time();
    $time_elapsed   = $cur_time - $time_ago;
    $seconds    = $time_elapsed ;
    $minutes    = round($time_elapsed / 60 );
    $hours      = round($time_elapsed / 3600);
    $days       = round($time_elapsed / 86400 );
    $weeks      = round($time_elapsed / 604800);
    $months     = round($time_elapsed / 2600640 );
    $years      = round($time_elapsed / 31207680 );
    // Seconds
    if($seconds <= 60){
        return "just now";
    }
    //Minutes
    else if($minutes <=60){
        if($minutes==1){
            return "one minute ago";
        }
        else{
            return "$minutes minutes ago";
        }
    }
    //Hours
    else if($hours <=24){
        if($hours==1){
            return "an hour ago";
        }else{
            return "$hours hrs ago";
        }
    }
    //Days
    else if($days <= 7){
        if($days==1){
            return "yesterday";
        }else{
            return "$days days ago";
        }
    }
    //Weeks
    else if($weeks <= 4.3){
        if($weeks==1){
            return "a week ago";
        }else{
            return "$weeks weeks ago";
        }
    }
    //Months
    else if($months <=12){
        if($months==1){
            return "a month ago";
        }else{
            return "$months months ago";
        }
    }
    //Years
    else{
        if($years==1){
            return "one year ago";
        }else{
            return "$years years ago";
        }
    }
}

No creo que afecte de manera notable. stackoverflow.com/questions/7895966/… Pero me doy cuenta de que, a medida que transcurre el tiempo y el evento ya dice "hace meses", tendrá que verificar muchos ifs (segundos, minutos, horas, días, semanas) . Por lo tanto, le sugiero que pueda envolver estas secciones if con otra externa si eso dice if ($ segundos <= 604800). De esa forma, un caso de hace meses no tendrá que verificar 4 ifs más ... nuevamente, los casos de menos de meses tendrán un extra si ... la elección es suya.
Capitán Rojo el

23

Esta es realmente una mejor solución que he encontrado. Utiliza jQuery pero funciona perfectamente. También se actualiza automáticamente similar a SO y Facebook, por lo que no tiene que actualizar la página para ver las actualizaciones.

Este complemento leerá su datetimeatributo en la <time>etiqueta y lo completará por usted.

e.g. "4 minutes ago" or "about 1 day ago

http://timeago.yarp.com/


Perfectamente trabajando y mostrando el resultado deseado en el tiempo IST
Vivek

17

No sé por qué nadie menciona el carbono todavía.

https://github.com/briannesbitt/Carbon

Esta es en realidad una extensión de php dateTime (que ya se usó aquí) y tiene: método diffForHumans. Entonces, todo lo que necesitas hacer es:

$dt = Carbon::parse('2012-9-5 23:26:11.123789');
echo $dt->diffForHumans();

más ejemplos: http://carbon.nesbot.com/docs/#api-humandiff

Ventajas de esta solución:

  • funciona para fechas futuras y devolverá algo así como en 2 meses, etc.
  • puede usar la localización para obtener otros idiomas y la pluralización funciona bien
  • si comenzará a usar Carbon para otras cosas, trabajar con fechas será tan fácil como nunca.

11

Encontré resultados como el siguiente feo:

1 año, 2 meses, 0 días, 0 horas, 53 minutos y 1 segundo

Por eso me di cuenta de una función que respeta los plurales, elimina los valores vacíos y, opcionalmente, es posible acortar la salida:

function since($timestamp, $level=6) {
    global $lang;
    $date = new DateTime();
    $date->setTimestamp($timestamp);
    $date = $date->diff(new DateTime());
    // build array
    $since = array_combine(array('year', 'month', 'day', 'hour', 'minute', 'second'), explode(',', $date->format('%y,%m,%d,%h,%i,%s')));
    // remove empty date values
    $since = array_filter($since);
    // output only the first x date values
    $since = array_slice($since, 0, $level);
    // build string
    $last_key = key(array_slice($since, -1, 1, true));
    $string = '';
    foreach ($since as $key => $val) {
        // separator
        if ($string) {
            $string .= $key != $last_key ? ', ' : ' ' . $lang['and'] . ' ';
        }
        // set plural
        $key .= $val > 1 ? 's' : '';
        // add date value
        $string .= $val . ' ' . $lang[ $key ];
    }
    return $string;
}

Se ve mucho mejor:

1 año, 2 meses, 53 minutos y 1 segundo

Opcionalmente, use $level = 2para acortarlo de la siguiente manera:

1 año y 2 meses

Elimine la $langparte si la necesita solo en inglés o edite esta traducción para satisfacer sus necesidades:

$lang = array(
    'second' => 'Sekunde',
    'seconds' => 'Sekunden',
    'minute' => 'Minute',
    'minutes' => 'Minuten',
    'hour' => 'Stunde',
    'hours' => 'Stunden',
    'day' => 'Tag',
    'days' => 'Tage',
    'month' => 'Monat',
    'months' => 'Monate',
    'year' => 'Jahr',
    'years' => 'Jahre',
    'and' => 'und',
);

De todos, este funciona bien para mí. Aunque no muestra ir o hace, pero funciona en ambos sentidos. Solución fácil: if ($ date-> invert> 0) {$ ending = "to go"; } else {$ ending = "ago"; } Simplemente agregue $ terminando a la cadena $.
Quentin Campbell

El uso de funciones json aquí es un gran éxito de rendimiento y completamente innecesario. Esta no es una buena solución.
zombat

@zombat Gracias por tus comentarios. Cambié la línea contra explodey array_combine.
mgutt

10
function humanTiming ($time)
        {

            $time = time() - $time; // to get the time since that moment
            $time = ($time<1)? 1 : $time;
            $tokens = array (
                31536000 => 'year',
                2592000 => 'month',
                604800 => 'week',
                86400 => 'day',
                3600 => 'hour',
                60 => 'minute',
                1 => 'second'
            );

            foreach ($tokens as $unit => $text) {
                if ($time < $unit) continue;
                $numberOfUnits = floor($time / $unit);
                return $numberOfUnits.' '.$text.(($numberOfUnits>1)?'s':'');
            }

        }

echo humanTiming( strtotime($mytimestring) );

1
Esto es realmente genial Gracias por compartir. Pero hay casos en los que la función devuelve $ numberOfUnits vacíos y solo muestra "ago". Aparentemente porque el valor es inferior a 1 segundo. En ese caso, si pudiera hacer que el valor predeterminado sea "justo ahora", sería perfecto.
Hezerac

6

Modifiqué un poco la función original (en mi opinión, más útil o lógica).

// display "X time" ago, $rcs is precision depth
function time_ago ($tm, $rcs = 0) {
  $cur_tm = time(); 
  $dif = $cur_tm - $tm;
  $pds = array('second','minute','hour','day','week','month','year','decade');
  $lngh = array(1,60,3600,86400,604800,2630880,31570560,315705600);

  for ($v = count($lngh) - 1; ($v >= 0) && (($no = $dif / $lngh[$v]) <= 1); $v--);
    if ($v < 0)
      $v = 0;
  $_tm = $cur_tm - ($dif % $lngh[$v]);

  $no = ($rcs ? floor($no) : round($no)); // if last denomination, round

  if ($no != 1)
    $pds[$v] .= 's';
  $x = $no . ' ' . $pds[$v];

  if (($rcs > 0) && ($v >= 1))
    $x .= ' ' . $this->time_ago($_tm, $rcs - 1);

  return $x;
}

Cualquier función que use matemáticas basadas en un calendario fijo es fundamentalmente defectuosa. Use el objeto Fecha, no haga matemáticas con el tiempo.
Chris Baker, el

2
@ Chris-Baker Cuando la mayoría de la gente usa este tipo de funciones, no es necesaria la precisión para el segundo. La función es precisa durante cortos períodos de tiempo y durante largos períodos de tiempo, estar cerca es más que suficiente.
Bobb Fwed

5

Hice esto y funciona bien, funciona tanto para la marca de tiempo de Unix como para la hora con 1470919932formato16-08-11 14:53:30

function timeAgo($time_ago) {
    $time_ago =  strtotime($time_ago) ? strtotime($time_ago) : $time_ago;
    $time  = time() - $time_ago;

switch($time):
// seconds
case $time <= 60;
return 'lessthan a minute ago';
// minutes
case $time >= 60 && $time < 3600;
return (round($time/60) == 1) ? 'a minute' : round($time/60).' minutes ago';
// hours
case $time >= 3600 && $time < 86400;
return (round($time/3600) == 1) ? 'a hour ago' : round($time/3600).' hours ago';
// days
case $time >= 86400 && $time < 604800;
return (round($time/86400) == 1) ? 'a day ago' : round($time/86400).' days ago';
// weeks
case $time >= 604800 && $time < 2600640;
return (round($time/604800) == 1) ? 'a week ago' : round($time/604800).' weeks ago';
// months
case $time >= 2600640 && $time < 31207680;
return (round($time/2600640) == 1) ? 'a month ago' : round($time/2600640).' months ago';
// years
case $time >= 31207680;
return (round($time/31207680) == 1) ? 'a year ago' : round($time/31207680).' years ago' ;

endswitch;
}

?>

¿No debería ser eso switch (true)aunque $timese evalúe true?
Mavelo

4

Solo para lanzar otra opción ...

Si bien prefiero publicar el método DateTime aquí , no me gustó el hecho de que mostrara 0 años, etc.

/* 
 * Returns a string stating how long ago this happened
 */

private function timeElapsedString($ptime){
    $diff = time() - $ptime;
    $calc_times = array();
    $timeleft   = array();

    // Prepare array, depending on the output we want to get.
    $calc_times[] = array('Year',   'Years',   31557600);
    $calc_times[] = array('Month',  'Months',  2592000);
    $calc_times[] = array('Day',    'Days',    86400);
    $calc_times[] = array('Hour',   'Hours',   3600);
    $calc_times[] = array('Minute', 'Minutes', 60);
    $calc_times[] = array('Second', 'Seconds', 1);

    foreach ($calc_times AS $timedata){
        list($time_sing, $time_plur, $offset) = $timedata;

        if ($diff >= $offset){
            $left = floor($diff / $offset);
            $diff -= ($left * $offset);
            $timeleft[] = "{$left} " . ($left == 1 ? $time_sing : $time_plur);
        }
    }

    return $timeleft ? (time() > $ptime ? null : '-') . implode(' ', $timeleft) : 0;
}

2

te ayuda a comprobarlo

   function calculate_time_span($seconds)
{  
 $year = floor($seconds /31556926);
$months = floor($seconds /2629743);
$week=floor($seconds /604800);
$day = floor($seconds /86400); 
$hours = floor($seconds / 3600);
 $mins = floor(($seconds - ($hours*3600)) / 60); 
$secs = floor($seconds % 60);
 if($seconds < 60) $time = $secs." seconds ago";
 else if($seconds < 3600 ) $time =($mins==1)?$mins."now":$mins." mins ago";
 else if($seconds < 86400) $time = ($hours==1)?$hours." hour ago":$hours." hours ago";
 else if($seconds < 604800) $time = ($day==1)?$day." day ago":$day." days ago";
 else if($seconds < 2629743) $time = ($week==1)?$week." week ago":$week." weeks ago";
 else if($seconds < 31556926) $time =($months==1)? $months." month ago":$months." months ago";
 else $time = ($year==1)? $year." year ago":$year." years ago";
return $time; 
}  
  $seconds = time() - strtotime($post->post_date); 
echo calculate_time_span($seconds); 

2

Usualmente uso esto para encontrar la diferencia entre currentypassed datetime stamp

SALIDA

//If difference is greater than 7 days
7 June 2019

// if difference is greater than 24 hours and less than 7 days
1 days ago
6 days ago

1 hour ago
23 hours ago

1 minute ago
58 minutes ago

1 second ago
20 seconds ago

CÓDIGO

//return current date time
function getCurrentDateTime(){
    //date_default_timezone_set("Asia/Calcutta");
    return date("Y-m-d H:i:s");
}
function getDateString($date){
    $dateArray = date_parse_from_format('Y/m/d', $date);
    $monthName = DateTime::createFromFormat('!m', $dateArray['month'])->format('F');
    return $dateArray['day'] . " " . $monthName  . " " . $dateArray['year'];
}

function getDateTimeDifferenceString($datetime){
    $currentDateTime = new DateTime(getCurrentDateTime());
    $passedDateTime = new DateTime($datetime);
    $interval = $currentDateTime->diff($passedDateTime);
    //$elapsed = $interval->format('%y years %m months %a days %h hours %i minutes %s seconds');
    $day = $interval->format('%a');
    $hour = $interval->format('%h');
    $min = $interval->format('%i');
    $seconds = $interval->format('%s');

    if($day > 7)
        return getDateString($datetime);
    else if($day >= 1 && $day <= 7 ){
        if($day == 1) return $day . " day ago";
        return $day . " days ago";
    }else if($hour >= 1 && $hour <= 24){
        if($hour == 1) return $hour . " hour ago";
        return $hour . " hours ago";
    }else if($min >= 1 && $min <= 60){
        if($min == 1) return $min . " minute ago";
        return $min . " minutes ago";
    }else if($seconds >= 1 && $seconds <= 60){
        if($seconds == 1) return $seconds . " second ago";
        return $seconds . " seconds ago";
    }
}

Gracias por esto. En realidad lo convertí a código C #.
Darrelk

Función indefinida getCurrentDateTime () para tu información
gfivehost

@gfivehost agregó el código de función, puede verificarlo ahora.
Vicky Salunkhe

1

Soy consciente de que hay varias respuestas aquí, pero esto es lo que se me ocurrió. Esto solo maneja los valores de DATETIME de MySQL según la pregunta original a la que respondía. La matriz $ a necesita algo de trabajo. Agradezco los comentarios sobre cómo mejorar. Llamar como:

echo time_elapsed_string ('2014-11-14 09:42:28');

function time_elapsed_string($ptime)
{
    // Past time as MySQL DATETIME value
    $ptime = strtotime($ptime);

    // Current time as MySQL DATETIME value
    $csqltime = date('Y-m-d H:i:s');

    // Current time as Unix timestamp
    $ctime = strtotime($csqltime); 

    // Elapsed time
    $etime = $ctime - $ptime;

    // If no elapsed time, return 0
    if ($etime < 1){
        return '0 seconds';
    }

    $a = array( 365 * 24 * 60 * 60  =>  'year',
                 30 * 24 * 60 * 60  =>  'month',
                      24 * 60 * 60  =>  'day',
                           60 * 60  =>  'hour',
                                60  =>  'minute',
                                 1  =>  'second'
    );

    $a_plural = array( 'year'   => 'years',
                       'month'  => 'months',
                       'day'    => 'days',
                       'hour'   => 'hours',
                       'minute' => 'minutes',
                       'second' => 'seconds'
    );

    foreach ($a as $secs => $str){
        // Divide elapsed time by seconds
        $d = $etime / $secs;
        if ($d >= 1){
            // Round to the next lowest integer 
            $r = floor($d);
            // Calculate time to remove from elapsed time
            $rtime = $r * $secs;
            // Recalculate and store elapsed time for next loop
            if(($etime - $rtime)  < 0){
                $etime -= ($r - 1) * $secs;
            }
            else{
                $etime -= $rtime;
            }
            // Create string to return
            $estring = $estring . $r . ' ' . ($r > 1 ? $a_plural[$str] : $str) . ' ';
        }
    }
    return $estring . ' ago';
}

1

Lo intenté y funciona bien para mí.

$datetime1 = new DateTime('2009-10-11');
$datetime2 = new DateTime('2009-10-10');
$difference = $datetime1->diff($datetime2);
echo formatOutput($difference);

function formatOutput($diff){
    /* function to return the highrst defference fount */
    if(!is_object($diff)){
        return;
    }

    if($diff->y > 0){
        return $diff->y .(" year".($diff->y > 1?"s":"")." ago");
    }

    if($diff->m > 0){
        return $diff->m .(" month".($diff->m > 1?"s":"")." ago");
    }

    if($diff->d > 0){
        return $diff->d .(" day".($diff->d > 1?"s":"")." ago");
    }

    if($diff->h > 0){
        return $diff->h .(" hour".($diff->h > 1?"s":"")." ago");
    }

    if($diff->i > 0){
        return $diff->i .(" minute".($diff->i > 1?"s":"")." ago");
    }

    if($diff->s > 0){
        return $diff->s .(" second".($diff->s > 1?"s":"")." ago");
    }
}

Consulte este enlace para referencia aquí

¡Gracias! y divertirse.


1

Esto es con lo que fui. Es una versión modificada de la publicación de Abbbas khan:

<?php

  function calculate_time_span($post_time)
  {  
  $seconds = time() - strtotime($post);
  $year = floor($seconds /31556926);
  $months = floor($seconds /2629743);
  $week=floor($seconds /604800);
  $day = floor($seconds /86400); 
  $hours = floor($seconds / 3600);
  $mins = floor(($seconds - ($hours*3600)) / 60); 
  $secs = floor($seconds % 60);
  if($seconds < 60) $time = $secs." seconds ago";
  else if($seconds < 3600 ) $time =($mins==1)?$mins."now":$mins." mins ago";
  else if($seconds < 86400) $time = ($hours==1)?$hours." hour ago":$hours." hours ago";
  else if($seconds < 604800) $time = ($day==1)?$day." day ago":$day." days ago";
  else if($seconds < 2629743) $time = ($week==1)?$week." week ago":$week." weeks ago";
  else if($seconds < 31556926) $time =($months==1)? $months." month ago":$months." months ago";
  else $time = ($year==1)? $year." year ago":$year." years ago";
  return $time; 
  }  



 // uses
 // $post_time="2017-12-05 02:05:12";
 // echo calculate_time_span($post_time); 

1

Muchas soluciones aquí no explicaron el redondeo. Por ejemplo:

El evento ocurrió a las 3 de la tarde hace dos días. Si está revisando a las 2pm, se mostrará hace un día. Si está revisando a las 4pm, se mostrará hace dos días.

Si está trabajando con unix time, esto ayuda:

// how long since event has passed in seconds
$secs = time() - $time_ago;

// how many seconds in a day
$sec_per_day = 60*60*24;

// days elapsed
$days_elapsed = floor($secs / $sec_per_day);

// how many seconds passed today
$today_seconds = date('G')*3600 + date('i') * 60 + date('s');

// how many seconds passed in the final day calculation
$remain_seconds = $secs % $sec_per_day;

if($today_seconds < $remain_seconds)
{
    $days_elapsed++;
}

echo 'The event was '.$days_ago.' days ago.';

No es perfecto si le preocupan los segundos de salto y el horario de verano.


1

Intente esto, lo encontré de mis viejos códigos, que muestra el resultado correcto

function ago($datefrom, $dateto = -1) {
    // Defaults and assume if 0 is passed in that
    // its an error rather than the epoch

    if ($datefrom == 0) {
        return "A long time ago";
    }
    if ($dateto == -1) {
        $dateto = time();
    }

    // Make the entered date into Unix timestamp from MySQL datetime field

    $datefrom = strtotime($datefrom);

    // Calculate the difference in seconds betweeen
    // the two timestamps

    $difference = $dateto - $datefrom;

    // Based on the interval, determine the
    // number of units between the two dates
    // From this point on, you would be hard
    // pushed telling the difference between
    // this function and DateDiff. If the $datediff
    // returned is 1, be sure to return the singular
    // of the unit, e.g. 'day' rather 'days'

    switch (true) {
        // If difference is less than 60 seconds,
        // seconds is a good interval of choice
        case(strtotime('-1 min', $dateto) < $datefrom):
            $datediff = $difference;
            $res = ($datediff == 1) ? $datediff . ' second' : $datediff . ' seconds';
            break;
        // If difference is between 60 seconds and
        // 60 minutes, minutes is a good interval
        case(strtotime('-1 hour', $dateto) < $datefrom):
            $datediff = floor($difference / 60);
            $res = ($datediff == 1) ? $datediff . ' minute' : $datediff . ' minutes';
            break;
        // If difference is between 1 hour and 24 hours
        // hours is a good interval
        case(strtotime('-1 day', $dateto) < $datefrom):
            $datediff = floor($difference / 60 / 60);
            $res = ($datediff == 1) ? $datediff . ' hour' : $datediff . ' hours';
            break;
        // If difference is between 1 day and 7 days
        // days is a good interval                
        case(strtotime('-1 week', $dateto) < $datefrom):
            $day_difference = 1;
            while (strtotime('-' . $day_difference . ' day', $dateto) >= $datefrom) {
                $day_difference++;
            }

            $datediff = $day_difference;
            $res = ($datediff == 1) ? 'yesterday' : $datediff . ' days';
            break;
        // If difference is between 1 week and 30 days
        // weeks is a good interval            
        case(strtotime('-1 month', $dateto) < $datefrom):
            $week_difference = 1;
            while (strtotime('-' . $week_difference . ' week', $dateto) >= $datefrom) {
                $week_difference++;
            }

            $datediff = $week_difference;
            $res = ($datediff == 1) ? 'last week' : $datediff . ' weeks';
            break;
        // If difference is between 30 days and 365 days
        // months is a good interval, again, the same thing
        // applies, if the 29th February happens to exist
        // between your 2 dates, the function will return
        // the 'incorrect' value for a day
        case(strtotime('-1 year', $dateto) < $datefrom):
            $months_difference = 1;
            while (strtotime('-' . $months_difference . ' month', $dateto) >= $datefrom) {
                $months_difference++;
            }

            $datediff = $months_difference;
            $res = ($datediff == 1) ? $datediff . ' month' : $datediff . ' months';

            break;
        // If difference is greater than or equal to 365
        // days, return year. This will be incorrect if
        // for example, you call the function on the 28th April
        // 2008 passing in 29th April 2007. It will return
        // 1 year ago when in actual fact (yawn!) not quite
        // a year has gone by
        case(strtotime('-1 year', $dateto) >= $datefrom):
            $year_difference = 1;
            while (strtotime('-' . $year_difference . ' year', $dateto) >= $datefrom) {
                $year_difference++;
            }

            $datediff = $year_difference;
            $res = ($datediff == 1) ? $datediff . ' year' : $datediff . ' years';
            break;
    }
    return $res;
}

Ejemplo: echo ago('2020-06-03 00:14:21 AM');

Salida: 6 days


0

Tendrá que tomar cada pieza individual de su marca de tiempo y convertirla en tiempo Unix. Por ejemplo, para la marca de tiempo, 2009-09-12 20:57:19.

(((2008-1970) * 365) + (8 * 30) +12) * 24 + 20 le daría una estimación aproximada de las horas desde el 1 de enero de 1970.

Tome ese número, multiplique por 60 y agregue 57 para obtener los minutos.

Toma eso, multiplica por 60 y suma 19.

Sin embargo, eso lo convertiría de manera muy aproximada e inexacta.

¿Hay alguna razón por la que no puedes tomar el tiempo normal de Unix para comenzar?


¿es mejor almacenarlo como unix en la tabla sql? Estoy usando la actualización de marca de tiempo automática de mysqls actualmente en una columna de marca de tiempo (que se puede cambiar a unix). ¿Solo estoy aprendiendo qué es mejor?
willdanceforfun

Seguro. Creo que el valor predeterminado para una tabla mySQL es el tipo al que hizo referencia, pero el tiempo Unix es mucho más práctico. Siempre puedes almacenarlo como int.
LukeWarm74

Su base de datos debe tener una función para convertir la fecha al formato UNIX. En mysql usa UNIX_TIMESTAMP (). Ah, y generalmente debe almacenar sus fechas como DATETIMEs en lugar de INTs, para que pueda usar las funciones sql para la manipulación de fechas.
CpnCrunch

Nunca, nunca debes usar las matemáticas a tiempo. Estás asumiendo un calendario fijo, que no existe. Use el objeto Fecha provisto en php para trabajar con ... fechas.
Chris Baker,

0

Hay algún problema con el tiempo de visualización de algunos idiomas, por ejemplo, en árabe hay 3 formatos necesarios para mostrar la fecha. Utilizo estas funciones en mis proyectos con la esperanza de que puedan ayudar a alguien (cualquier sugerencia o mejora me agradará :))

/**
 *
 * @param   string $date1 
 * @param   string $date2 the date that you want to compare with $date1
 * @param   int $level  
 * @param   bool $absolute  
 */

function app_date_diff( $date1, $date2, $level = 3, $absolute = false ) {

    $date1 = date_create($date1);   
    $date2 = date_create($date2);
    $diff = date_diff( $date1, $date2, $absolute );

    $d = [
        'invert' => $diff->invert
    ];  

    $diffs = [
        'y' => $diff->y, 
        'm' => $diff->m, 
        'd' => $diff->d
    ];

    $level_reached = 0;

    foreach($diffs as $k=>$v) {

        if($level_reached >= $level) {
            break;
        }

        if($v > 0) {
            $d[$k] = $v;
            $level_reached++;
        }

    }

    return  $d;

}

/**
 * 
 */

function date_timestring( $periods, $format = 'latin', $separator = ',' ) {

    $formats = [
        'latin' => [
            'y' => ['year','years'],
            'm' => ['month','months'],
            'd' => ['day','days']
        ],
        'arabic' => [
            'y' => ['سنة','سنتين','سنوات'],
            'm' => ['شهر','شهرين','شهور'],
            'd' => ['يوم','يومين','أيام']
        ]
    ];

    $formats = $formats[$format];

    $string = [];

    foreach($periods as $period=>$value) {

        if(!isset($formats[$period])) {
            continue;
        }

        $string[$period] = $value.' ';
        if($format == 'arabic') {
            if($value == 2) {
                $string[$period] = $formats[$period][1];
            }elseif($value > 2 && $value <= 10) {
                $string[$period] .= $formats[$period][2];
            }else{
                $string[$period] .= $formats[$period][0];
            }

        }elseif($format == 'latin') {
            $string[$period] .= ($value > 1) ? $formats[$period][1] : $formats[$period][0];
        }

    }

    return implode($separator, $string);


}

function timeago( $date ) {

    $today = date('Y-m-d h:i:s');

    $diff = app_date_diff($date,$today,2);

    if($diff['invert'] == 1) {
        return '';
    }

    unset($diff[0]);

    $date_timestring = date_timestring($diff,'latin');

    return 'About '.$date_timestring;

}

$date1 = date('Y-m-d');
$date2 = '2018-05-14';

$diff = timeago($date2);
echo $diff;

-1
$time_ago = ' ';
$time = time() - $time; // to get the time since that moment
$tokens = array (
31536000 => 'year',2592000 => 'month',604800 => 'week',86400 => 'day',3600 => 'hour',
60  => 'minute',1 => 'second');
foreach ($tokens as $unit => $text) {
if ($time < $unit)continue;
$numberOfUnits = floor($time / $unit);
$time_ago = ' '.$time_ago. $numberOfUnits.' '.$text.(($numberOfUnits>1)?'s':'').'  ';
$time = $time % $unit;}echo $time_ago;

-1

Aquí está mi solución, compruebe y modifique según sus requisitos

function getHowLongAgo($date, $display = array('Year', 'Month', 'Day', 'Hour', 'Minute', 'Second'), $ago = '') {
        date_default_timezone_set('Australia/Sydney');
        $timestamp = strtotime($date);
        $timestamp = (int) $timestamp;
        $current_time = time();
        $diff = $current_time - $timestamp;

        //intervals in seconds
        $intervals = array(
            'year' => 31556926, 'month' => 2629744, 'week' => 604800, 'day' => 86400, 'hour' => 3600, 'minute' => 60
        );

        //now we just find the difference
        if ($diff == 0) {
            return ' Just now ';
        }

        if ($diff < 60) {
            return $diff == 1 ? $diff . ' second ago ' : $diff . ' seconds ago ';
        }

        if ($diff >= 60 && $diff < $intervals['hour']) {
            $diff = floor($diff / $intervals['minute']);
            return $diff == 1 ? $diff . ' minute ago ' : $diff . ' minutes ago ';
        }

        if ($diff >= $intervals['hour'] && $diff < $intervals['day']) {
            $diff = floor($diff / $intervals['hour']);
            return $diff == 1 ? $diff . ' hour ago ' : $diff . ' hours ago ';
        }

        if ($diff >= $intervals['day'] && $diff < $intervals['week']) {
            $diff = floor($diff / $intervals['day']);
            return $diff == 1 ? $diff . ' day ago ' : $diff . ' days ago ';
        }

        if ($diff >= $intervals['week'] && $diff < $intervals['month']) {
            $diff = floor($diff / $intervals['week']);
            return $diff == 1 ? $diff . ' week ago ' : $diff . ' weeks ago ';
        }

        if ($diff >= $intervals['month'] && $diff < $intervals['year']) {
            $diff = floor($diff / $intervals['month']);
            return $diff == 1 ? $diff . ' month ago ' : $diff . ' months ago ';
        }

        if ($diff >= $intervals['year']) {
            $diff = floor($diff / $intervals['year']);
            return $diff == 1 ? $diff . ' year ago ' : $diff . ' years ago ';
        }
    }

Gracias


-1
# This function prints the difference between two php datetime objects
# in a more human readable form
# inputs should be like strtotime($date)
function humanizeDateDiffference($now,$otherDate=null,$offset=null){
    if($otherDate != null){
        $offset = $now - $otherDate;
    }
    if($offset != null){
        $deltaS = $offset%60;
        $offset /= 60;
        $deltaM = $offset%60;
        $offset /= 60;
        $deltaH = $offset%24;
        $offset /= 24;
        $deltaD = ($offset > 1)?ceil($offset):$offset;      
    } else{
        throw new Exception("Must supply otherdate or offset (from now)");
    }
    if($deltaD > 1){
        if($deltaD > 365){
            $years = ceil($deltaD/365);
            if($years ==1){
                return "last year"; 
            } else{
                return "<br>$years years ago";
            }   
        }
        if($deltaD > 6){
            return date('d-M',strtotime("$deltaD days ago"));
        }       
        return "$deltaD days ago";
    }
    if($deltaD == 1){
        return "Yesterday";
    }
    if($deltaH == 1){
        return "last hour";
    }
    if($deltaM == 1){
        return "last minute";
    }
    if($deltaH > 0){
        return $deltaH." hours ago";
    }
    if($deltaM > 0){
        return $deltaM." minutes ago";
    }
    else{
        return "few seconds ago";
    }
}

-1

Esta función no está diseñada para usarse en inglés. Traduje las palabras en inglés. Esto necesita más reparaciones antes de usarlo en inglés.

function ago($d) {
$ts = time() - strtotime(str_replace("-","/",$d));

        if($ts>315360000) $val = round($ts/31536000,0).' year';
        else if($ts>94608000) $val = round($ts/31536000,0).' years';
        else if($ts>63072000) $val = ' two years';
        else if($ts>31536000) $val = ' a year';

        else if($ts>24192000) $val = round($ts/2419200,0).' month';
        else if($ts>7257600) $val = round($ts/2419200,0).' months';
        else if($ts>4838400) $val = ' two months';
        else if($ts>2419200) $val = ' a month';


        else if($ts>6048000) $val = round($ts/604800,0).' week';
        else if($ts>1814400) $val = round($ts/604800,0).' weeks';
        else if($ts>1209600) $val = ' two weeks';
        else if($ts>604800) $val = ' a week';

        else if($ts>864000) $val = round($ts/86400,0).' day';
        else if($ts>259200) $val = round($ts/86400,0).' days';
        else if($ts>172800) $val = ' two days';
        else if($ts>86400) $val = ' a day';

        else if($ts>36000) $val = round($ts/3600,0).' year';
        else if($ts>10800) $val = round($ts/3600,0).' years';
        else if($ts>7200) $val = ' two years';
        else if($ts>3600) $val = ' a year';

        else if($ts>600) $val = round($ts/60,0).' minute';
        else if($ts>180) $val = round($ts/60,0).' minutes';
        else if($ts>120) $val = ' two minutes';
        else if($ts>60) $val = ' a minute';

        else if($ts>10) $val = round($ts,0).' second';
        else if($ts>2) $val = round($ts,0).' seconds';
        else if($ts>1) $val = ' two seconds';
        else $val = $ts.' a second';


        return $val;
    }

-1

Uso de:

echo elapsed_time('2016-05-09 17:00:00'); // 18 saat 8 dakika önce yazıldı.

Función:

function elapsed_time($time){// Nekadar zaman geçmiş

        $diff = time() - strtotime($time); 

        $sec = $diff;
        $min = floor($diff/60);
        $hour = floor($diff/(60*60));
        $hour_min = floor($min - ($hour*60));
        $day = floor($diff/(60*60*24));
        $day_hour = floor($hour - ($day*24));
        $week = floor($diff/(60*60*24*7));
        $mon = floor($diff/(60*60*24*7*4));
        $year = floor($diff/(60*60*24*7*4*12));

        //difference calculate to string
        if($sec < (60*5)){
            return 'şimdi yazıldı.';
        }elseif($min < 60){
            return 'biraz önce yazıldı.';
        }elseif($hour < 24){
            return $hour.' saat '.$hour_min.' dakika önce yazıldı.';
        }elseif($day < 7){
            if($day_hour!=0){$day_hour=$day_hour.' saat ';}else{$day_hour='';}
            return $day.' gün '.$day_hour.'önce yazıldı.';
        }elseif($week < 4){
            return $week.' hafta önce yazıldı.';
        }elseif($mon < 12){
            return $mon.' ay önce yazıldı.';
        }else{
            return $year.' yıl önce yazıldı.';
        }
    }

un mes es más largo que 28 días, un año más largo que 52 semanas.
Augwa

-1

Respuesta ligeramente modificada desde arriba:

  $commentTime = strtotime($whatever)
  $today       = strtotime('today');
  $yesterday   = strtotime('yesterday');
  $todaysHours = strtotime('now') - strtotime('today');

private function timeElapsedString(
    $commentTime,
    $todaysHours,
    $today,
    $yesterday
) {
    $tokens = array(
        31536000 => 'year',
        2592000 => 'month',
        604800 => 'week',
        86400 => 'day',
        3600 => 'hour',
        60 => 'minute',
        1 => 'second'
    );
    $time = time() - $commentTime;
    $time = ($time < 1) ? 1 : $time;
    if ($commentTime >= $today || $commentTime < $yesterday) {
        foreach ($tokens as $unit => $text) {
            if ($time < $unit) {
                continue;
            }
            if ($text == 'day') {
                $numberOfUnits = floor(($time - $todaysHours) / $unit) + 1;
            } else {
                $numberOfUnits = floor(($time)/ $unit);
            }
            return $numberOfUnits . ' ' . $text . (($numberOfUnits > 1) ? 's' : '') . ' ago';
        }
    } else {
        return 'Yesterday';
    }
}

-2

La siguiente es una solución muy simple y extremadamente eficiente.

function timeElapsed($originalTime){

        $timeElapsed=time()-$originalTime;

        /*
          You can change the values of the following 2 variables 
          based on your opinion. For 100% accuracy, you can call
          php's cal_days_in_month() and do some additional coding
          using the values you get for each month. After all the
          coding, your final answer will be approximately equal to
          mine. That is why it is okay to simply use the average
          values below.
        */
        $averageNumbDaysPerMonth=(365.242/12);
        $averageNumbWeeksPerMonth=($averageNumbDaysPerMonth/7);

        $time1=(((($timeElapsed/60)/60)/24)/365.242);
        $time2=floor($time1);//Years
        $time3=($time1-$time2)*(365.242);
        $time4=($time3/$averageNumbDaysPerMonth);
        $time5=floor($time4);//Months
        $time6=($time4-$time5)*$averageNumbWeeksPerMonth;
        $time7=floor($time6);//Weeks
        $time8=($time6-$time7)*7;
        $time9=floor($time8);//Days
        $time10=($time8-$time9)*24;
        $time11=floor($time10);//Hours
        $time12=($time10-$time11)*60;
        $time13=floor($time12);//Minutes
        $time14=($time12-$time13)*60;
        $time15=round($time14);//Seconds

        $timeElapsed=$time2 . 'yrs ' . $time5 . 'months ' . $time7 . 
                     'weeks ' . $time9 .  'days ' . $time11 . 'hrs '
                     . $time13 . 'mins and ' . $time15 . 'secs.';

        return $timeElapsed;

}

tiempo de eco transcurrido (1201570814);

Salida de muestra:

6 años 4 meses 3 semanas 4 días 12 horas 40 minutos y 36 segundos.


-2

Aquí está mi solución para un módulo de notificación que construí hace algún tiempo. Devuelve un resultado similar al menú desplegable de notificaciones de Facebook (por ejemplo, hace 1 día, justo ahora, etc.).

public function getTimeDifference($time) {
    //Let's set the current time
    $currentTime = date('Y-m-d H:i:s');
    $toTime = strtotime($currentTime);

    //And the time the notification was set
    $fromTime = strtotime($time);

    //Now calc the difference between the two
    $timeDiff = floor(abs($toTime - $fromTime) / 60);

    //Now we need find out whether or not the time difference needs to be in
    //minutes, hours, or days
    if ($timeDiff < 2) {
        $timeDiff = "Just now";
    } elseif ($timeDiff > 2 && $timeDiff < 60) {
        $timeDiff = floor(abs($timeDiff)) . " minutes ago";
    } elseif ($timeDiff > 60 && $timeDiff < 120) {
        $timeDiff = floor(abs($timeDiff / 60)) . " hour ago";
    } elseif ($timeDiff < 1440) {
        $timeDiff = floor(abs($timeDiff / 60)) . " hours ago";
    } elseif ($timeDiff > 1440 && $timeDiff < 2880) {
        $timeDiff = floor(abs($timeDiff / 1440)) . " day ago";
    } elseif ($timeDiff > 2880) {
        $timeDiff = floor(abs($timeDiff / 1440)) . " days ago";
    }

    return $timeDiff;
}

-2

simplemente pasa la fecha y hora a esta función. se imprimiría en el formato de hace tiempo para usted

date_default_timezone_set('your-time-zone');
function convert($datetime){
  $time=strtotime($datetime);
  $diff=time()-$time;
  $diff/=60;
  $var1=floor($diff);
  $var=$var1<=1 ? 'min' : 'mins';
  if($diff>=60){
    $diff/=60;
    $var1=floor($diff);
    $var=$var1<=1 ? 'hr' : 'hrs';
    if($diff>=24){$diff/=24;$var1=floor($diff);$var=$var1<=1 ? 'day' : 'days';
    if($diff>=30.4375){$diff/=30.4375;$var1=floor($diff);$var=$var1<=1 ? 'month' : 'months';
    if($diff>=12){$diff/=12;$var1=floor($diff);$var=$var1<=1 ? 'year' : 'years';}}}}
    echo $var1,' ',$var,' ago';
  }

-3

Estoy usando la siguiente función durante varios años. Y está funcionando bien:

function timeDifference($timestamp)
{
    $otherDate=$timestamp;
    $now=@date("Y-m-d H:i:s");

    $secondDifference=@strtotime($now)-@strtotime($otherDate);
    $extra="";
    if ($secondDifference == 2592000) { 
    // months 
    $difference = $secondDifference/2592000; 
    $difference = round($difference,0); 
    if ($difference>1) { $extra="s"; } 
    $difference = $difference." month".$extra." ago"; 
}else if($secondDifference > 2592000)
    {$difference=timestamp($timestamp);} 
elseif ($secondDifference >= 604800) { 
    // weeks 
    $difference = $secondDifference/604800; 
    $difference = round($difference,0); 
    if ($difference>1) { $extra="s"; } 
    $difference = $difference." week".$extra." ago"; 
} 
elseif ($secondDifference >= 86400) { 
    // days 
    $difference = $secondDifference/86400; 
    $difference = round($difference,0); 
    if ($difference>1) { $extra="s"; } 
    $difference = $difference." day".$extra." ago"; 
} 
elseif ($secondDifference >= 3600) { 
    // hours 

    $difference = $secondDifference/3600; 
    $difference = round($difference,0); 
    if ($difference>1) { $extra="s"; } 
    $difference = $difference." hour".$extra." ago"; 
} 
elseif ($secondDifference < 3600) { 
    // hours 
    // for seconds (less than minute)
    if($secondDifference<=60)
    {       
        if($secondDifference==0)
        {
            $secondDifference=1;
        }
        if ($secondDifference>1) { $extra="s"; }
        $difference = $secondDifference." second".$extra." ago"; 

    }
    else
    {

$difference = $secondDifference/60; 
        if ($difference>1) { $extra="s"; }else{$extra="";}
        $difference = round($difference,0); 
        $difference = $difference." minute".$extra." ago"; 
    }
} 

$FinalDifference = $difference; 
return $FinalDifference;
}
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.