PHP 如何查找自日期时间以来经过的时间?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/2915864/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-25 08:07:58  来源:igfitidea点击:

PHP How to find the time elapsed since a date time?

phpdatetimetimestamprelative-time-span

提问by Mithun Sreedharan

How to find the time elapsed since a date time stamp like 2010-04-28 17:25:43, final out put text should be like xx Minutes Ago/xx Days Ago

如何查找自日期时间戳之类的经过时间2010-04-28 17:25:43,最终输出文本应为xx Minutes Ago/xx Days Ago

回答by arnorhs

Most of the answers seem focused around converting the date from a string to time. It seems you're mostly thinking about getting the date into the '5 days ago' format, etc.. right?

大多数答案似乎都集中在将日期从字符串转换为时间。看来您主要是考虑将日期转换为“5 天前”格式等。对吗?

This is how I'd go about doing that:

这就是我要做的事情:

$time = strtotime('2010-04-28 17:25:43');

echo 'event happened '.humanTiming($time).' ago';

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':'');
    }

}

I haven't tested that, but it should work.

我还没有测试过,但它应该可以工作。

The result would look like

结果看起来像

event happened 4 days ago

or

或者

event happened 1 minute ago

cheers

干杯

回答by Aman

Want to share php function which results in grammatically correct Facebook like human readable time format.

想要分享 php 函数,它导致语法正确的 Facebook 喜欢人类可读的时间格式。

Example:

例子:

echo get_time_ago(strtotime('now'));

Result:

结果:

less than 1 minute ago

不到 1 分钟前

function get_time_ago($time_stamp)
{
    $time_difference = strtotime('now') - $time_stamp;

    if ($time_difference >= 60 * 60 * 24 * 365.242199)
    {
        /*
         * 60 seconds/minute * 60 minutes/hour * 24 hours/day * 365.242199 days/year
         * This means that the time difference is 1 year or more
         */
        return get_time_ago_string($time_stamp, 60 * 60 * 24 * 365.242199, 'year');
    }
    elseif ($time_difference >= 60 * 60 * 24 * 30.4368499)
    {
        /*
         * 60 seconds/minute * 60 minutes/hour * 24 hours/day * 30.4368499 days/month
         * This means that the time difference is 1 month or more
         */
        return get_time_ago_string($time_stamp, 60 * 60 * 24 * 30.4368499, 'month');
    }
    elseif ($time_difference >= 60 * 60 * 24 * 7)
    {
        /*
         * 60 seconds/minute * 60 minutes/hour * 24 hours/day * 7 days/week
         * This means that the time difference is 1 week or more
         */
        return get_time_ago_string($time_stamp, 60 * 60 * 24 * 7, 'week');
    }
    elseif ($time_difference >= 60 * 60 * 24)
    {
        /*
         * 60 seconds/minute * 60 minutes/hour * 24 hours/day
         * This means that the time difference is 1 day or more
         */
        return get_time_ago_string($time_stamp, 60 * 60 * 24, 'day');
    }
    elseif ($time_difference >= 60 * 60)
    {
        /*
         * 60 seconds/minute * 60 minutes/hour
         * This means that the time difference is 1 hour or more
         */
        return get_time_ago_string($time_stamp, 60 * 60, 'hour');
    }
    else
    {
        /*
         * 60 seconds/minute
         * This means that the time difference is a matter of minutes
         */
        return get_time_ago_string($time_stamp, 60, 'minute');
    }
}

function get_time_ago_string($time_stamp, $divisor, $time_unit)
{
    $time_difference = strtotime("now") - $time_stamp;
    $time_units      = floor($time_difference / $divisor);

    settype($time_units, 'string');

    if ($time_units === '0')
    {
        return 'less than 1 ' . $time_unit . ' ago';
    }
    elseif ($time_units === '1')
    {
        return '1 ' . $time_unit . ' ago';
    }
    else
    {
        /*
         * More than "1" $time_unit. This is the "plural" message.
         */
        // TODO: This pluralizes the time unit, which is done by adding "s" at the end; this will not work for i18n!
        return $time_units . ' ' . $time_unit . 's ago';
    }
}

回答by JoeR

I think I have a function which should do what you want:

我想我有一个功能可以做你想做的事:

function time2string($timeline) {
    $periods = array('day' => 86400, 'hour' => 3600, 'minute' => 60, 'second' => 1);

    foreach($periods AS $name => $seconds){
        $num = floor($timeline / $seconds);
        $timeline -= ($num * $seconds);
        $ret .= $num.' '.$name.(($num > 1) ? 's' : '').' ';
    }

    return trim($ret);
}

Simply apply it to the difference between time()and strtotime('2010-04-28 17:25:43')as so:

只需将它应用到之间的差异time(),并strtotime('2010-04-28 17:25:43')为这样:

print time2string(time()-strtotime('2010-04-28 17:25:43')).' ago';

回答by fyrye

Be warned, the majority of the mathematically calculated examples have a hard limit of 2038-01-18dates and will not work with fictional dates.

请注意,大多数数学计算的示例都有严格的2038-01-18日期限制,并且不适用于虚构的日期。

As there was a lack of DateTimeand DateIntervalbased examples, I wanted to provide a multi-purpose function that satisfies the OP's need and others wanting compound elapsed periods, such as 1 month 2 days ago. Along with a bunch of other use cases, such as a limit to display the date instead of the elapsed time, or to filter out portions of the elapsed time result.

由于缺乏DateTimeDateInterval基础的例子,我想提供一个多用途的功能来满足 OP 的需要和其他人想要复合经过时间,例如1 month 2 days ago. 连同一堆其他用例,例如限制显示日期而不是经过时间,或过滤掉部分经过时间结果。

Additionally the majority of the examples assume elapsed is from the current time, where the below function allows for it to be overridden with the desired end date.

此外,大多数示例都假设经过的时间是从当前时间开始的,下面的函数允许它被所需的结束日期覆盖。

/**
 * multi-purpose function to calculate the time elapsed between $start and optional $end
 * @param string|null $start the date string to start calculation
 * @param string|null $end the date string to end calculation
 * @param string $suffix the suffix string to include in the calculated string
 * @param string $format the format of the resulting date if limit is reached or no periods were found
 * @param string $separator the separator between periods to use when filter is not true
 * @param null|string $limit date string to stop calculations on and display the date if reached - ex: 1 month
 * @param bool|array $filter false to display all periods, true to display first period matching the minimum, or array of periods to display ['year', 'month']
 * @param int $minimum the minimum value needed to include a period
 * @return string
 */
function elapsedTimeString($start, $end = null, $limit = null, $filter = true, $suffix = 'ago', $format = 'Y-m-d', $separator = ' ', $minimum = 1)
{
    $dates = (object) array(
        'start' => new DateTime($start ? : 'now'),
        'end' => new DateTime($end ? : 'now'),
        'intervals' => array('y' => 'year', 'm' => 'month', 'd' => 'day', 'h' => 'hour', 'i' => 'minute', 's' => 'second'),
        'periods' => array()
    );
    $elapsed = (object) array(
        'interval' => $dates->start->diff($dates->end),
        'unknown' => 'unknown'
    );
    if ($elapsed->interval->invert === 1) {
        return trim('0 seconds ' . $suffix);
    }
    if (false === empty($limit)) {
        $dates->limit = new DateTime($limit);
        if (date_create()->add($elapsed->interval) > $dates->limit) {
            return $dates->start->format($format) ? : $elapsed->unknown;
        }
    }
    if (true === is_array($filter)) {
        $dates->intervals = array_intersect($dates->intervals, $filter);
        $filter = false;
    }
    foreach ($dates->intervals as $period => $name) {
        $value = $elapsed->interval->$period;
        if ($value >= $minimum) {
            $dates->periods[] = vsprintf('%1$s %2$s%3$s', array($value, $name, ($value !== 1 ? 's' : '')));
            if (true === $filter) {
                break;
            }
        }
    }
    if (false === empty($dates->periods)) {
        return trim(vsprintf('%1$s %2$s', array(implode($separator, $dates->periods), $suffix)));
    }

    return $dates->start->format($format) ? : $elapsed->unknown;
}

One thing to note - the retrieved intervals for the supplied filter values do not carry over to the next period. The filter merely displays the resulting value of the supplied periods and does not recalculate the periods to display only the desired filter total.

需要注意的一件事 - 提供的过滤器值的检索间隔不会延续到下一个时期。过滤器仅显示提供的周期的结果值,并且不会重新计算周期以仅显示所需的过滤器总数。



Usage

用法

For the OP's need of displaying the highest period (as of 2015-02-24).

对于 OP 需要显示最高时期(截至 2015-02-24)。

echo elapsedTimeString('2010-04-26');
/** 4 years ago */

To display compound periods and supply a custom end date (note the lack of time supplied and fictional dates).

显示复合期间并提供自定义结束日期(注意缺少提供的时间和虚构日期)

echo elapsedTimeString('1920-01-01', '2500-02-24', null, false);
/** 580 years 1 month 23 days ago */

To display the result of filtered periods (ordering of array doesn't matter).

显示过滤周期的结果(数组的顺序无关紧要)

echo elapsedTimeString('2010-05-26', '2012-02-24', null, ['month', 'year']);
/** 1 year 8 months ago */

To display the start date in the supplied format (default Y-m-d) if the limit is reached.

如果达到限制,则以提供的格式(默认 Ymd)显示开始日期。

echo elapsedTimeString('2010-05-26', '2012-02-24', '1 year');
/** 2010-05-26 */

There are bunch of other use cases. It can also easily be adapted to accept unix timestamps and/or DateInterval objects for the start, end, or limit arguments.

还有很多其他用例。它还可以很容易地进行调整以接受开始、结束或限制参数的 Unix 时间戳和/或 DateInterval 对象。

回答by Tessmore

If you use the php Datetime class you could use:

如果您使用 php Datetime 类,您可以使用:

function time_ago(Datetime $date) {
  $time_ago = '';

  $diff = $date->diff(new Datetime('now'));


  if (($t = $diff->format("%m")) > 0)
    $time_ago = $t . ' months';
  else if (($t = $diff->format("%d")) > 0)
    $time_ago = $t . ' days';
  else if (($t = $diff->format("%H")) > 0)
    $time_ago = $t . ' hours';
  else
    $time_ago = 'minutes';

  return $time_ago . ' ago (' . $date->format('M j, Y') . ')';
}

回答by David Headrick

I liked Mithun's code, but I tweaked it a bit to make it give more reasonable answers.

我喜欢 Mithun 的代码,但我对其进行了一些调整以使其给出更合理的答案。

function getTimeSince($eventTime)
{
    $totaldelay = time() - strtotime($eventTime);
    if($totaldelay <= 0)
    {
        return '';
    }
    else
    {
        $first = '';
        $marker = 0;
        if($years=floor($totaldelay/31536000))
        {
            $totaldelay = $totaldelay % 31536000;
            $plural = '';
            if ($years > 1) $plural='s';
            $interval = $years." year".$plural;
            $timesince = $timesince.$first.$interval;
            if ($marker) return $timesince;
            $marker = 1;
            $first = ", ";
        }
        if($months=floor($totaldelay/2628000))
        {
            $totaldelay = $totaldelay % 2628000;
            $plural = '';
            if ($months > 1) $plural='s';
            $interval = $months." month".$plural;
            $timesince = $timesince.$first.$interval;
            if ($marker) return $timesince;
            $marker = 1;
            $first = ", ";
        }
        if($days=floor($totaldelay/86400))
        {
            $totaldelay = $totaldelay % 86400;
            $plural = '';
            if ($days > 1) $plural='s';
            $interval = $days." day".$plural;
            $timesince = $timesince.$first.$interval;
            if ($marker) return $timesince;
            $marker = 1;
            $first = ", ";
        }
        if ($marker) return $timesince;
        if($hours=floor($totaldelay/3600))
        {
            $totaldelay = $totaldelay % 3600;
            $plural = '';
            if ($hours > 1) $plural='s';
            $interval = $hours." hour".$plural;
            $timesince = $timesince.$first.$interval;
            if ($marker) return $timesince;
            $marker = 1;
            $first = ", ";

        }
        if($minutes=floor($totaldelay/60))
        {
            $totaldelay = $totaldelay % 60;
            $plural = '';
            if ($minutes > 1) $plural='s';
            $interval = $minutes." minute".$plural;
            $timesince = $timesince.$first.$interval;
            if ($marker) return $timesince;
            $first = ", ";
        }
        if($seconds=floor($totaldelay/1))
        {
            $totaldelay = $totaldelay % 1;
            $plural = '';
            if ($seconds > 1) $plural='s';
            $interval = $seconds." second".$plural;
            $timesince = $timesince.$first.$interval;
        }        
        return $timesince;

    }
}

回答by Aran

To improve upon @arnorhs answer I've added in the ability to have a more precise result so if you wanted years, months, days & hours for instance since the user joined.

为了改进@arnorhs 的答案,我添加了获得更精确结果的能力,因此如果您想要例如自用户加入以来的年、月、日和小时。

I've added a new parameter to allow you to specify the number of points of precision you wish to have returned.

我添加了一个新参数,允许您指定希望返回的精度点数。

function get_friendly_time_ago($distant_timestamp, $max_units = 3) {
    $i = 0;
    $time = time() - $distant_timestamp; // to get the time since that moment
    $tokens = [
        31536000 => 'year',
        2592000 => 'month',
        604800 => 'week',
        86400 => 'day',
        3600 => 'hour',
        60 => 'minute',
        1 => 'second'
    ];

    $responses = [];
    while ($i < $max_units && $time > 0) {
        foreach ($tokens as $unit => $text) {
            if ($time < $unit) {
                continue;
            }
            $i++;
            $numberOfUnits = floor($time / $unit);

            $responses[] = $numberOfUnits . ' ' . $text . (($numberOfUnits > 1) ? 's' : '');
            $time -= ($unit * $numberOfUnits);
            break;
        }
    }

    if (!empty($responses)) {
        return implode(', ', $responses) . ' ago';
    }

    return 'Just now';
}

回答by khan Asim

Use This one and you can get the

使用这个,你可以得到

    $previousDate = '2013-7-26 17:01:10';
    $startdate = new DateTime($previousDate);
    $endDate   = new DateTime('now');
    $interval  = $endDate->diff($startdate);
    echo$interval->format('%y years, %m months, %d days');

Refer this http://ca2.php.net/manual/en/dateinterval.format.php

请参阅此 http://ca2.php.net/manual/en/dateinterval.format.php

回答by raveren

Try one of these repos:

尝试以下存储库之一:

https://github.com/salavert/time-ago-in-words

https://github.com/salavert/time-ago-in-words

https://github.com/jimmiw/php-time-ago

https://github.com/jimmiw/php-time-ago

I just started using the latter, does the trick, but no stackoverflow-style fallback on exact date when the date in question is too far away, nor is there support for future dates - and the API is a little funky, but at least it works seemingly flawlessly and is maintained...

我刚开始使用后者,有诀窍,但是当所讨论的日期太远时,在确切日期上没有 stackoverflow 式的回退,也不支持未来的日期——而且 API 有点时髦,但至少它是工作似乎完美无缺,并得到维护......

回答by Evernoob

Convert [saved_date] to timestamp. Get current timestamp.

将 [saved_date] 转换为时间戳。获取当前时间戳。

current timestamp - [saved_date] timestamp.

当前时间戳 - [saved_date] 时间戳。

Then you can format it with date();

然后你可以用 date() 格式化它;

You can normally convert most date formats to timestamps with the strtotime() function.

您通常可以使用 strtotime() 函数将大多数日期格式转换为时间戳。