Как рассчитать прошедшее время с помощью Joda-Time?

Мне нужно рассчитать время, прошедшее с одной конкретной даты до настоящего момента, и отобразить его в том же формате, что и вопросы StackOverflow, т. е.:

15s ago
2min ago
2hours ago
2days ago
25th Dec 08

Знаете ли вы, как добиться этого с помощью библиотеки Java Joda-Time? Есть ли вспомогательный метод, который уже реализует его, или я должен сам написать алгоритм?


person fabien7474    schedule 01.02.2010    source источник
comment
25 декабря 2008 года — это не время, прошедшее с одной конкретной даты до сегодняшнего дня (которую вы написали жирным шрифтом;)   -  person SyntaxT3rr0r    schedule 01.02.2010
comment
Я знаю. Но SO отображает время, заданное таким образом. Если период достаточно длинный, то отображается точная дата.   -  person fabien7474    schedule 02.02.2010
comment
Я очень недоволен датами обработки StackOverflow. Сначала вы получаете очень точные цифры (37 секунд назад), но вскоре они становятся очень расплывчатыми (2 дня назад). Только после того, как время будет отображаться в абсолютном формате, вы снова увидите точную (по крайней мере, с точностью до минут) дату и время. Я считаю, что такого рода относительная информация полезна только в дополнение к абсолютной, но не может заменить ее.   -  person Svante    schedule 02.02.2010
comment
Вы можете получить точную дату и время во всплывающей подсказке. Просто наведите курсор на дату и время :)   -  person BalusC    schedule 02.02.2010
comment
Joda-Time не очень хорошо подходит для печати относительного (прошедшего) времени, когда вам нужны дополнительные функции. Принятый ответ в порядке, но не локализуемый (только для английского языка). Если вам нужна поддержка локализации, есть лучшие сторонние библиотеки. ocpsoft/PrettyTime — лучший вариант, но он работает только со старым классом java.util.Date. Однако моя библиотека Time4J ИМХО является лучшей библиотекой для печати любого относительного раз (формат назад) или раз в формате, например, 3 месяца, 4 дня. Он также локализуется фактически для 72 языков.   -  person Meno Hochschild    schedule 15.04.2016


Ответы (6)


Чтобы рассчитать прошедшее время с помощью JodaTime, используйте Period. Чтобы отформатировать прошедшее время в желаемом человеческом представлении, используйте PeriodFormatter, который можно создать с помощью PeriodFormatterBuilder.

Вот пример запуска:

DateTime myBirthDate = new DateTime(1978, 3, 26, 12, 35, 0, 0);
DateTime now = new DateTime();
Period period = new Period(myBirthDate, now);

PeriodFormatter formatter = new PeriodFormatterBuilder()
    .appendSeconds().appendSuffix(" seconds ago\n")
    .appendMinutes().appendSuffix(" minutes ago\n")
    .appendHours().appendSuffix(" hours ago\n")
    .appendDays().appendSuffix(" days ago\n")
    .appendWeeks().appendSuffix(" weeks ago\n")
    .appendMonths().appendSuffix(" months ago\n")
    .appendYears().appendSuffix(" years ago\n")
    .printZeroNever()
    .toFormatter();

String elapsed = formatter.print(period);
System.out.println(elapsed);

Это печатает сейчас

3 seconds ago
51 minutes ago
7 hours ago
6 days ago
10 months ago
31 years ago

(Кашель, старый, кашель) Вы видите, что я также принял во внимание месяцы и годы и настроил его так, чтобы он опускал значения, когда они равны нулю.

person BalusC    schedule 01.02.2010
comment
Спасибо. Я использовал ваш код в качестве основы для моего алгоритма. В основном я отображаю прошедшее время с 1 полем (или максимум 2). Если кому-то интересен код, я могу опубликовать его здесь в качестве ответа. Он также совместим с i18. - person fabien7474; 02.02.2010
comment
Я протестировал приведенный выше код и обнаружил, что форматировщику не хватает поля недели - дни переносятся после дня 6. Поэтому я добавил: .appendWeeks().appendSuffix( недели назад\n) - person Mike Hopper; 23.11.2010
comment
@fabien7474 Как вы адаптировали его, чтобы отображалось только одно поле? Пожалуйста, опубликуйте это как ответ. - person karl; 07.10.2013
comment
@fabien7474 действительно, как вы адаптировали его, чтобы отображалось только одно поле? - person oko; 20.01.2014
comment
Можно ли использовать его и для будущих событий? то есть через 2 часа, завтра в 9:00 и т. д.? - person Michael; 25.05.2015
comment
Я обнаружил, что существует статический метод PeriodFormat.wordBased(), который возвращает предварительно созданный модуль форматирования на основе слов. В отличие от этого примера, он обрабатывает единицы времени в единственном и множественном числе, но вместо относительного «назад...» использует отрицательные значения. - person csab; 22.08.2015
comment
Проверьте этот суть, чтобы показать только одно поле. - person Laranjeiro; 20.07.2016
comment
При использовании продолжительности вы можете использовать Duration.asPeriod(). - person Keith Tyler; 21.05.2021

Используйте PrettyTime для простого прошедшего времени.

Я попробовал HumanTime, как ответил @sfussenegger, и использовал Period JodaTime, но самый простой и Я обнаружил, что самым чистым методом для удобочитаемого прошедшего времени является библиотека PrettyTime.

Вот пара простых примеров с вводом и выводом:

Пять минут назад

DateTime fiveMinutesAgo = DateTime.now().minusMinutes( 5 );

new PrettyTime().format( fiveMinutesAgo.toDate() );

// Outputs: "5 minutes ago"

Некоторое время назад

DateTime birthday = new DateTime(1978, 3, 26, 12, 35, 0, 0);

new PrettyTime().format( birthday.toDate() );

// Outputs: "4 decades ago"

ВНИМАНИЕ! Я пробовал экспериментировать с более точными функциями библиотеки, но это дает некоторые странные результаты, поэтому используйте ее с осторожностью и в проектах, не угрожающих жизни.

JP

person Joshua Pinter    schedule 16.08.2014

Вы можете сделать это с помощью PeriodFormatter, но вам не нужно прилагать усилия для создания собственного PeriodFormatBuilder, как в других ответах. Если это подходит для вашего случая, вы можете просто использовать средство форматирования по умолчанию:

Period period = new Period(startDate, endDate);
System.out.println(PeriodFormat.getDefault().print(period))

(подсказка к этот ответ на аналогичный вопрос, я публикую перекрестные сообщения для удобства обнаружения)

person snappieT    schedule 07.02.2014
comment
Я только что попробовал это, и он дает разбивку периода по всем полям на миллисекунды, поэтому getDefault() не так уж полезен. - person NealeU; 18.02.2015
comment
Я только что попробовал это, и он дает разбивку периода по всем полям в миллисекундах, поэтому getDefault() полезно. (Спасибо @snappieT) - person Synesso; 02.09.2015
comment
Это лаконично и достаточно для большинства случаев использования. - person James Selvakumar; 28.10.2016

Существует небольшой вспомогательный класс под названием HumanTime, которым я очень доволен.

person sfussenegger    schedule 01.02.2010
comment
Отлично. Добавление простого примера ввода и вывода к вашему ответу было бы очень полезно. - person Joshua Pinter; 16.08.2014

Это использует временную метку mysql, чтобы получить прошедшее время. Единственное и множественное число управляется. Отображать только максимальное время.

ПРИМЕЧАНИЕ. Установите собственный часовой пояс.

String getElapsedTime(String strMysqlTimestamp) {
    
    DateTimeFormatter formatter = DateTimeFormat.forPattern("YYYY-MM-dd HH:mm:ss.S");
    DateTime mysqlDate = formatter.parseDateTime(strMysqlTimestamp).
                         withZone(DateTimeZone.forID("Asia/Kuala_Lumpur"));
    
    DateTime now = new DateTime();
    Period period = new Period(mysqlDate, now);
    
    int seconds = period.getSeconds();
    int minutes = period.getMinutes();
    int hours = period.getHours();
    int days = period.getDays();
    int weeks = period.getWeeks();
    int months = period.getMonths();
    int years = period.getYears();
    
    String elapsedTime = "";
    if (years != 0)
        if (years == 1)
            elapsedTime = years + " year ago";
        else
            elapsedTime = years + " years ago";
    else if (months != 0)
        if (months == 1)
            elapsedTime = months + " month ago";
        else
            elapsedTime = months + " months ago";
    else if (weeks != 0)
        if (weeks == 1)
            elapsedTime = weeks + " week ago";
        else
            elapsedTime = weeks + " weeks ago";
    else if (days != 0)
        if (days == 1)
            elapsedTime = days + " day ago";
        else
            elapsedTime = days + " days ago";
    else if (hours != 0)
        if (hours == 1)
            elapsedTime = hours + " hour ago";
        else
            elapsedTime = hours + " hours ago";
    else if (minutes != 0)
        if (minutes == 1)
            elapsedTime = minutes + " minute ago";
        else
            elapsedTime = minutes + " minutes ago";
    else if (seconds != 0)
        if (seconds == 1)
            elapsedTime = seconds + " second ago";
        else
            elapsedTime = seconds + " seconds ago";   
    
    return elapsedTime;
} 
person jumper rbk    schedule 04.01.2021

Вот мое решение с использованием joda time.

private static final int SECOND_MILLIS = 1000;
private static final int MINUTE_MILLIS = 60 * SECOND_MILLIS;
private static final int HOUR_MILLIS = 60 * MINUTE_MILLIS;
private static final int DAY_MILLIS = 24 * HOUR_MILLIS;

public static String getTimeAgo(long time)
{
    if(time < 1000000000000L)
    {
        time *= 1000;
    }

    long now = System.currentTimeMillis();

    if(time > now || time <= 0)
    {
        return null;
    }

    final long diff = now - time;

    if(diff < MINUTE_MILLIS)
    {
        return "just now";
    }
    else if(diff < 2 * MINUTE_MILLIS)
    {
        return "a minute ago";
    }
    else if(diff < 50 * MINUTE_MILLIS)
    {
        return diff / MINUTE_MILLIS + " minutes ago";
    }
    else if(diff < 90 * MINUTE_MILLIS)
    {
        return "an hour ago";
    }
    else if(diff < 24 * HOUR_MILLIS)
    {
        return diff / HOUR_MILLIS + " hours ago";
    }
    else if(diff < 48 * HOUR_MILLIS)
    {
        return "yesterday";
    }
    else
    {
        return diff / DAY_MILLIS + " days ago";
    }
}

Как использовать метод:

Просто вызовите метод и перейдите во времени в milliseconds.

Например:

long now = System.currentTimeMillis();
getTimeAgo(now);
person 4xMafole    schedule 03.06.2021