Относительное форматирование даты всегда выдает «3 часа назад» - PullRequest
3 голосов
/ 28 июня 2011

Я вычисляю интервал дат между указанной датой и текущей датой, используя php. Я делаю это, чтобы печатать дружеские временные метки, такие как A few mins ago и 2 hours ago

Когда я прихожу на часть часов, я получаю что-то очень забавное в php. Ниже приведен полный рабочий код, но при замене детали hours на этот код она всегда печатается 3 часа.

Заданная константа ДАТА

// The current date timestamp
define('DATE', time());

Код ошибки здесь:

//Only the hours part that' doing something weird
case ($interval >= 3600 && $interval < 86400) :
            $return = ( date('H', $interval) < 2)
                ? (int)date('H', $interval) . ' hour ago'
                : (int)date('H', $interval) . ' hours ago';
            break;

Он прерывается, когда указанная дата, скажем, в этом случае, дата создания чуть более часа назад, в результате чего получается интервал, равный 3660 секундам. Кажется, что вызов метода date date('H', 3660) приводит к 03. Разве это не должно приводить к 01? это ведь чуть более часа.

Рабочий код здесь:

public static function getTimeInterval($date)
{
    $interval = DATE - $date;

    $return = '';

    switch ( $interval )
    {
        case ($interval <= 60) :
            $return = 'a few secs ago';
            break;

        case ($interval > 60 && $interval < 3600) :
            $return = (int)date('i', $interval) . ' mins ago';
            break;

        case ($interval >= 3600 && $interval < 86400) :
            $return = ( abs((date('G', DATE) - date('G', $date))) < 2)
                ? abs((date('G', DATE) - date('G', $date))) . ' hour ago'
                : abs((date('G', DATE) - date('G', $date))) . ' hours ago';
            break;

        case ($interval >= 86400 && $interval < 604800) :
            $return = ( (int)date('j', $interval) === 1)
                ? (int)date('j', $interval) . ' day ago'
                : (int)date('j', $interval) . ' days ago';
            break;

        case ($interval > 604800 && $interval <= 2592000) :
            $return = 'A few weeks ago';
            break;
        case ($interval > 2592000) :
            $return = date('n', $interval) . ' months ago';
            break;
        case ($interval > 31536000) :
            $return = 'Over a year ago';
            break;

    }

    return $return;

}

Ответы [ 6 ]

3 голосов
/ 28 июня 2011

Проверьте этот код, он работает хорошо:

function do_plurals($nb, $str)
{
    return $nb > 1 ? $str . 's' : $str;
}


function dates_interval_text(DateTime $start, DateTime $end)
{
    $interval = $end->diff($start);

    $format = array();
    if ($interval->y !== 0)
    {
        $format[] = "%y " . do_plurals($interval->y, "year");
    }
    if ($interval->m !== 0)
    {
        $format[] = "%m " . do_plurals($interval->m, "month");
    }
    if ($interval->d !== 0)
    {
        $format[] = "%d " . do_plurals($interval->d, "day");
    }
    if ($interval->h !== 0)
    {
        $format[] = "%h " . do_plurals($interval->h, "hour");
    }
    if ($interval->i !== 0)
    {
        $format[] = "%i " . do_plurals($interval->i, "minute");
    }
    if (!count($format))
    {
        return "less than a minute ago";
    }

    // We use the two biggest parts
    if (count($format) > 1)
    {
        $format = array_shift($format) . " and " . array_shift($format);
    }
    else
    {
        $format = array_pop($format);
    }

    // Prepend 'since ' or whatever you like
    return $interval->format($format) . ' ago';
}

Он дает результаты, такие как 2 hours and 3 minutes ago

3 голосов
/ 28 июня 2011

результат date () зависит от вашего часового пояса.Вы можете изменить это поведение, установив часовой пояс вручную с помощью date_default_timezone_set ()

2 голосов
/ 28 июня 2011

Второй аргумент date - это не длительность, а отметка времени . date отвечает на вопрос "N секунд после 01.01.1970 00:00 UTC, который час?" и ответ на этот вопрос дается в вашем часовом поясе , поэтому смещение вашего часового пояса добавляется к ответу.

Используйте date('Z'), чтобы найти смещение часового пояса в секундах. Или, что еще лучше, используйте floor($time/3600) для вычисления часов.

2 голосов
/ 28 июня 2011

date('H', 3660) приводит к 01 для меня. Возможно, часовой пояс, который вы используете в данный момент. Это может быть на локальном уровне (приложение) или глобальном уровне (php config). Может быть, даже это ваша ОС. Извините, я не могу больше помочь с тем, какие настройки PHP искать и еще много чего.

1 голос
/ 28 июня 2011

Мой первый вопрос: откуда вы берете время / метку времени / дату / время?

В нашей компании мы работаем на нескольких серверах в Германии, а размещенные на них приложения предназначены для Пакистана (GMT +5).мы используем эту функцию, которая использует метку времени Unix для возврата «читабельного» даты: -

/**
 * @desc Converts UNIX Time into human readable time like '1 hour', 3 weeks', etc.
 * @param number $timestamp
 * @return string
 */
function readable_time($timestamp, $num_times = 2)  {
    // this returns human readable time when it was uploaded
    $times = array (
    31536000 => 'year', 2592000 => 'month',
    604800 => 'week', 86400 => 'day',
    3600 => 'hour', 60 => 'minute', 1 => 'second'
    );
    $now = time ();
    $secs = $now - $timestamp;
    // Fix so that something is always displayed
    if ($secs == 0) $secs = 1;
    $count = 0; $time = '';
    foreach ( $times as $key => $value )    {
        if ($secs >= $key)  {
            // time found
            $s = '';
            $time .= floor ( $secs / $key );
            if ((floor ( $secs / $key ) != 1))  $s = 's';
            $time .= ' ' . $value . $s;
            $count ++;
            $secs = $secs % $key;
            if ($count > $num_times - 1 || $secs == 0) break;
            else $time .= ', ';
        }
    }
    return ($time != "") ? $time." ago" : "now";
}

Изменяя переменную $num_times, мы можем получить что-то вроде «4 месяца, 3 дня, 2».часы, 3 минуты, 15 секунд назад "(в этом примере значение переменной равно 5).

Логически отметка времени поступает из базы данных - в нашем случае MySQL - поэтому мы используем другую функцию, которая принимает отметку времени MySQLи преобразует его в метку времени Unix: -

/**
 * @desc Converts UNIX Time into human readable time like '1 hour', 3 weeks', etc.
 * @param number $timestamp
 * @return string
 */
function RelativeTime($timestamp)   {
    $difference = time() - $timestamp;
    $periods = array("sec", "min", "hour", "day", "week", "month", "years", "decade");
    $lengths = array("60", "60", "24", "7", "4.35", "12", "10");
    if ($difference > 0)    { // this was in the past
        $ending = "ago";
    }   else    { // this was in the future
        $difference = -$difference;
        $ending = "to go";
    }
    for($j = 0; $difference >= $lengths[$j]; $j++) $difference /= $lengths[$j];
    $difference = round($difference);
    if($difference != 1) $periods[$j].= "s";
    $text = "$difference $periods[$j] $ending";
    return $text;
}

Удачи!

1 голос
/ 28 июня 2011

Ваш код работает нормально.В том, как вы это называете, есть ошибка.Он работает очень хорошо, когда $ date передается как метка времени Unix, например, $ date = time () - 1 * 60 * 60 (для 1 часа назад).

http://codepad.org/HS25qThK

$aboutHourAgo = time() - 2.5*60*60;   // 2 and half hours ago
var_dump(getTimeInterval($aboutHourAgo));
...