如何计算Java中的“time ago”?

时间:2010-10-04 21:29:53

标签: java date time datediff relative-time-span

在Ruby on Rails中,有一项功能允许您使用任何日期并打印出“很久以前”的日期。

例如:

8 minutes ago
8 hours ago
8 days ago
8 months ago
8 years ago

在Java中有一种简单的方法吗?

31 个答案:

答案 0 :(得分:159)

查看PrettyTime库。

使用起来非常简单:

import org.ocpsoft.prettytime.PrettyTime;

PrettyTime p = new PrettyTime();
System.out.println(p.format(new Date()));
// prints "moments ago"

您还可以传入国际化消息的区域设置:

PrettyTime p = new PrettyTime(new Locale("fr"));
System.out.println(p.format(new Date()));
// prints "à l'instant"

如评论中所述,Android在android.text.format.DateUtils类中内置了此功能。

答案 1 :(得分:69)

您是否考虑过TimeUnit枚举?对于这种事情它可能非常有用

    try {
        SimpleDateFormat format = new SimpleDateFormat("dd/MM/yyyy");
        Date past = format.parse("01/10/2010");
        Date now = new Date();

        System.out.println(TimeUnit.MILLISECONDS.toMillis(now.getTime() - past.getTime()) + " milliseconds ago");
        System.out.println(TimeUnit.MILLISECONDS.toMinutes(now.getTime() - past.getTime()) + " minutes ago");
        System.out.println(TimeUnit.MILLISECONDS.toHours(now.getTime() - past.getTime()) + " hours ago");
        System.out.println(TimeUnit.MILLISECONDS.toDays(now.getTime() - past.getTime()) + " days ago");
    }
    catch (Exception j){
        j.printStackTrace();
    }

答案 2 :(得分:42)

  public class TimeUtils {

      public final static long ONE_SECOND = 1000;
      public final static long SECONDS = 60;

      public final static long ONE_MINUTE = ONE_SECOND * 60;
      public final static long MINUTES = 60;

      public final static long ONE_HOUR = ONE_MINUTE * 60;
      public final static long HOURS = 24;

      public final static long ONE_DAY = ONE_HOUR * 24;

      private TimeUtils() {
      }

      /**
       * converts time (in milliseconds) to human-readable format
       *  "<w> days, <x> hours, <y> minutes and (z) seconds"
       */
      public static String millisToLongDHMS(long duration) {
        StringBuffer res = new StringBuffer();
        long temp = 0;
        if (duration >= ONE_SECOND) {
          temp = duration / ONE_DAY;
          if (temp > 0) {
            duration -= temp * ONE_DAY;
            res.append(temp).append(" day").append(temp > 1 ? "s" : "")
               .append(duration >= ONE_MINUTE ? ", " : "");
          }

          temp = duration / ONE_HOUR;
          if (temp > 0) {
            duration -= temp * ONE_HOUR;
            res.append(temp).append(" hour").append(temp > 1 ? "s" : "")
               .append(duration >= ONE_MINUTE ? ", " : "");
          }

          temp = duration / ONE_MINUTE;
          if (temp > 0) {
            duration -= temp * ONE_MINUTE;
            res.append(temp).append(" minute").append(temp > 1 ? "s" : "");
          }

          if (!res.toString().equals("") && duration >= ONE_SECOND) {
            res.append(" and ");
          }

          temp = duration / ONE_SECOND;
          if (temp > 0) {
            res.append(temp).append(" second").append(temp > 1 ? "s" : "");
          }
          return res.toString();
        } else {
          return "0 second";
        }
      }


      public static void main(String args[]) {
        System.out.println(millisToLongDHMS(123));
        System.out.println(millisToLongDHMS((5 * ONE_SECOND) + 123));
        System.out.println(millisToLongDHMS(ONE_DAY + ONE_HOUR));
        System.out.println(millisToLongDHMS(ONE_DAY + 2 * ONE_SECOND));
        System.out.println(millisToLongDHMS(ONE_DAY + ONE_HOUR + (2 * ONE_MINUTE)));
        System.out.println(millisToLongDHMS((4 * ONE_DAY) + (3 * ONE_HOUR)
            + (2 * ONE_MINUTE) + ONE_SECOND));
        System.out.println(millisToLongDHMS((5 * ONE_DAY) + (4 * ONE_HOUR)
            + ONE_MINUTE + (23 * ONE_SECOND) + 123));
        System.out.println(millisToLongDHMS(42 * ONE_DAY));
        /*
          output :
                0 second
                5 seconds
                1 day, 1 hour
                1 day and 2 seconds
                1 day, 1 hour, 2 minutes
                4 days, 3 hours, 2 minutes and 1 second
                5 days, 4 hours, 1 minute and 23 seconds
                42 days
         */
    }
}

更多@ Format a duration in milliseconds into a human-readable format

答案 3 :(得分:39)

我接受RealHowTo和Ben J的回答并制作我自己的版本:

public class TimeAgo {
public static final List<Long> times = Arrays.asList(
        TimeUnit.DAYS.toMillis(365),
        TimeUnit.DAYS.toMillis(30),
        TimeUnit.DAYS.toMillis(1),
        TimeUnit.HOURS.toMillis(1),
        TimeUnit.MINUTES.toMillis(1),
        TimeUnit.SECONDS.toMillis(1) );
public static final List<String> timesString = Arrays.asList("year","month","day","hour","minute","second");

public static String toDuration(long duration) {

    StringBuffer res = new StringBuffer();
    for(int i=0;i< TimeAgo.times.size(); i++) {
        Long current = TimeAgo.times.get(i);
        long temp = duration/current;
        if(temp>0) {
            res.append(temp).append(" ").append( TimeAgo.timesString.get(i) ).append(temp != 1 ? "s" : "").append(" ago");
            break;
        }
    }
    if("".equals(res.toString()))
        return "0 seconds ago";
    else
        return res.toString();
}
public static void main(String args[]) {
    System.out.println(toDuration(123));
    System.out.println(toDuration(1230));
    System.out.println(toDuration(12300));
    System.out.println(toDuration(123000));
    System.out.println(toDuration(1230000));
    System.out.println(toDuration(12300000));
    System.out.println(toDuration(123000000));
    System.out.println(toDuration(1230000000));
    System.out.println(toDuration(12300000000L));
    System.out.println(toDuration(123000000000L));
}}

将打印以下内容

0 second ago
1 second ago
12 seconds ago
2 minutes ago
20 minutes ago
3 hours ago
1 day ago
14 days ago
4 months ago
3 years ago

答案 4 :(得分:9)

这是基于RealHowTo的答案,所以如果你喜欢它,也要给他/她一些爱。

此清理版本允许您指定您可能感兴趣的时间范围。

它还处理“和”部分有点不同。我经常发现在使用分隔符连接字符串时,更容易跳过复杂的逻辑,并在完成后删除最后一个分隔符。

import java.util.concurrent.TimeUnit;
import static java.util.concurrent.TimeUnit.MILLISECONDS;

public class TimeUtils {

    /**
     * Converts time to a human readable format within the specified range
     *
     * @param duration the time in milliseconds to be converted
     * @param max      the highest time unit of interest
     * @param min      the lowest time unit of interest
     */
    public static String formatMillis(long duration, TimeUnit max, TimeUnit min) {
        StringBuilder res = new StringBuilder();

        TimeUnit current = max;

        while (duration > 0) {
            long temp = current.convert(duration, MILLISECONDS);

            if (temp > 0) {
                duration -= current.toMillis(temp);
                res.append(temp).append(" ").append(current.name().toLowerCase());
                if (temp < 2) res.deleteCharAt(res.length() - 1);
                res.append(", ");
            }

            if (current == min) break;

            current = TimeUnit.values()[current.ordinal() - 1];
        }

        // clean up our formatting....

        // we never got a hit, the time is lower than we care about
        if (res.lastIndexOf(", ") < 0) return "0 " + min.name().toLowerCase();

        // yank trailing  ", "
        res.deleteCharAt(res.length() - 2);

        //  convert last ", " to " and"
        int i = res.lastIndexOf(", ");
        if (i > 0) {
            res.deleteCharAt(i);
            res.insert(i, " and");
        }

        return res.toString();
    }
}

给它一个旋转的小代码:

import static java.util.concurrent.TimeUnit.*;

public class Main {

    public static void main(String args[]) {
        long[] durations = new long[]{
            123,
            SECONDS.toMillis(5) + 123,
            DAYS.toMillis(1) + HOURS.toMillis(1),
            DAYS.toMillis(1) + SECONDS.toMillis(2),
            DAYS.toMillis(1) + HOURS.toMillis(1) + MINUTES.toMillis(2),
            DAYS.toMillis(4) + HOURS.toMillis(3) + MINUTES.toMillis(2) + SECONDS.toMillis(1),
            DAYS.toMillis(5) + HOURS.toMillis(4) + MINUTES.toMillis(1) + SECONDS.toMillis(23) + 123,
            DAYS.toMillis(42)
        };

        for (long duration : durations) {
            System.out.println(TimeUtils.formatMillis(duration, DAYS, SECONDS));
        }

        System.out.println("\nAgain in only hours and minutes\n");

        for (long duration : durations) {
            System.out.println(TimeUtils.formatMillis(duration, HOURS, MINUTES));
        }
    }

}

将输出以下内容:

0 seconds
5 seconds 
1 day and 1 hour 
1 day and 2 seconds 
1 day, 1 hour and 2 minutes 
4 days, 3 hours, 2 minutes and 1 second 
5 days, 4 hours, 1 minute and 23 seconds 
42 days 

Again in only hours and minutes

0 minutes
0 minutes
25 hours 
24 hours 
25 hours and 2 minutes 
99 hours and 2 minutes 
124 hours and 1 minute 
1008 hours 

如果有人需要它,这里有一个类可以转换任何字符串,如上面的back into milliseconds。这对于允许人们在可读文本中指定各种事物的超时非常有用。

答案 5 :(得分:9)

有一种简单的方法可以做到这一点:

假设你想要20分钟前的时间:

Long minutesAgo = new Long(20);
Date date = new Date();
Date dateIn_X_MinAgo = new Date (date.getTime() - minutesAgo*60*1000);

就是这样..

答案 6 :(得分:6)

java.time

使用Java 8及更高版本中内置的java.time框架。

LocalDateTime t1 = LocalDateTime.of(2015, 1, 1, 0, 0, 0);
LocalDateTime t2 = LocalDateTime.now();
Period period = Period.between(t1.toLocalDate(), t2.toLocalDate());
Duration duration = Duration.between(t1, t2);

System.out.println("First January 2015 is " + period.getYears() + " years ago");
System.out.println("First January 2015 is " + period.getMonths() + " months ago");
System.out.println("First January 2015 is " + period.getDays() + " days ago");
System.out.println("First January 2015 is " + duration.toHours() + " hours ago");
System.out.println("First January 2015 is " + duration.toMinutes() + " minutes ago");

答案 7 :(得分:5)

如果您正在寻找简单的“今天”,“昨天”或“x天前”。

private String getDaysAgo(Date date){
    long days = (new Date().getTime() - date.getTime()) / 86400000;

    if(days == 0) return "Today";
    else if(days == 1) return "Yesterday";
    else return days + " days ago";
}

答案 8 :(得分:5)

关于内置解决方案:

Java没有任何内置支持来格式化相对时间,也不支持Java-8及其新包java.time。如果你只需要英语而不需要其他任何东西,那么只有手工制作的解决方案才可以接受 - 请参阅@RealHowTo的答案(尽管它有一个很大的缺点,就是不考虑将即时增量转换为当地时间的时区单位!)。无论如何,如果你想避免本土复杂的解决方法,特别是对于其他语言环境,那么你需要一个外部库。

在后一种情况下,我建议使用我的库Time4J(或Android上的Time4A)。它提供最大的灵活性和最大的i18n-power 。为此,班net.time4j.PrettyTime有七种方法printRelativeTime...(...)。使用测试时钟作为时间源的示例:

TimeSource<?> clock = () -> PlainTimestamp.of(2015, 8, 1, 10, 24, 5).atUTC();
Moment moment = PlainTimestamp.of(2015, 8, 1, 17, 0).atUTC(); // our input
String durationInDays =
  PrettyTime.of(Locale.GERMAN).withReferenceClock(clock).printRelative(
    moment,
    Timezone.of(EUROPE.BERLIN),
    TimeUnit.DAYS); // controlling the precision
System.out.println(durationInDays); // heute (german word for today)

使用java.time.Instant作为输入的另一个例子:

String relativeTime = 
  PrettyTime.of(Locale.ENGLISH)
    .printRelativeInStdTimezone(Moment.from(Instant.EPOCH));
System.out.println(relativeTime); // 45 years ago

此库支持通过其最新版本(v4.17) 80种语言以及一些特定国家/地区的语言环境(特别是西班牙语,英语,阿拉伯语,法语)。 i18n数据主要基于最新的CLDR-version v29 。使用此库的其他重要原因是支持多个规则(通常与其他语言环境中的英语不同),缩写格式(例如:“1秒之前“)以及考虑时区的表达方式。 Time4J甚至可以在相对时间的计算中意识到诸如闰秒之类的奇特细节(不是很重要,但它形成了与期望视野相关的信息)。 与Java-8的兼容性存在,因为java.time.Instantjava.time.Period等类型的转换方法很容易获得。

有任何缺点吗?只有两个。

  • 图书馆不小(也因为它的i18n数据库很大)。
  • API并不为人所知,因此社区知识和支持尚不可用,否则所提供的文档非常详细和全面。

(紧凑型)替代方案:

如果您寻找更小的解决方案,并且不需要这么多功能,并且愿意容忍与i18n-data相关的可能的质量问题,那么:

  • 我建议 ocpsoft / PrettyTime (实际支持32种语言(很快34?),仅适用于java.util.Date - 请参阅@ataylor的答案。具有巨大社区背景的行业标准CLDR(来自Unicode联盟)不幸地不是i18n数据的基础,因此数据的进一步增强或改进可能需要一段时间......

  • 如果您使用的是Android,那么助手类 android.text.format.DateUtils 是一种纤薄的内置替代方案(请参阅此处的其他评论和答案,其缺点是没有多年和几个月的支持。而且我确信只有极少数人喜欢这个助手类的API风格。

  • 如果您是 Joda-Time 的粉丝,那么您可以查看其类PeriodFormat(在版本v2.9.4中支持14种语言,另一方面: Joda-Time肯定也不紧凑,所以我在这里提到它只是为了完整性)。这个库不是真正的答案,因为根本不支持相对时间。您至少需要附加文字“之前”(并从生成的列表格式中手动剥离所有较低的单位 - 笨拙)。与Time4J或Android-DateUtils不同,它没有特别支持缩写或从相对时间到绝对时间表示的自动切换。与PrettyTime一样,它完全依赖于Java社区的私有成员对其i18n数据的未经证实的贡献。

答案 9 :(得分:4)

我创建了一个Java timeago插件的简单jquery-timeago端口,可以满足您的要求。

TimeAgo time = new TimeAgo();
String minutes = time.timeAgo(System.currentTimeMillis() - (15*60*1000)); // returns "15 minutes ago"

答案 10 :(得分:3)

joda-time包的概念为Periods。您可以使用Periods和DateTimes进行算术运算。

来自docs

public boolean isRentalOverdue(DateTime datetimeRented) {
  Period rentalPeriod = new  Period().withDays(2).withHours(12);
  return datetimeRented.plus(rentalPeriod).isBeforeNow();
}

答案 11 :(得分:3)

您可以使用此功能计算时间前

 private String timeAgo(long time_ago) {
        long cur_time = (Calendar.getInstance().getTimeInMillis()) / 1000;
        long time_elapsed = cur_time - time_ago;
        long seconds = time_elapsed;
        int minutes = Math.round(time_elapsed / 60);
        int hours = Math.round(time_elapsed / 3600);
        int days = Math.round(time_elapsed / 86400);
        int weeks = Math.round(time_elapsed / 604800);
        int months = Math.round(time_elapsed / 2600640);
        int years = Math.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";
            }
        }
    }

1)这里time_ago是微秒

答案 12 :(得分:3)

如果您正在为Android开发应用,它会为所有此类要求提供实用程序类DateUtils。看一下DateUtils#getRelativeTimeSpanString()实用程序方法。

来自

的文档

CharSequence getRelativeTimeSpanString(很长一段时间,很长时间,很长的minResolution)

  

返回描述&#39; time&#39;的字符串。作为一个相对于现在&#39;的时间。过去的时间跨度格式为&#34; 42分钟前&#34;。未来的时间跨度格式为&#34;在42分钟内&#34;。

您将timestamp 时间System.currentTimeMillis()作为现在传递给您。 minResolution可让您指定要报告的最小时间跨度。

  

例如,过去3秒的时间将报告为&#34; 0分钟前&#34;如果将其设置为MINUTE_IN_MILLIS。传递0,MINUTE_IN_MILLIS,HOUR_IN_MILLIS,DAY_IN_MILLIS,WEEK_IN_MILLIS等中的一个。

答案 13 :(得分:2)

它不漂亮......但我能想到的最接近的是使用Joda-Time(如本文所述:How to calculate elapsed time from now with Joda Time?

答案 14 :(得分:2)

基于这里的一堆答案,我为我的用例创建了以下内容。

使用示例:

String relativeDate = String.valueOf(
                TimeUtils.getRelativeTime( 1000L * myTimeInMillis() ));
import java.util.Arrays;
import java.util.List;

import static java.util.concurrent.TimeUnit.DAYS;
import static java.util.concurrent.TimeUnit.HOURS;
import static java.util.concurrent.TimeUnit.MINUTES;
import static java.util.concurrent.TimeUnit.SECONDS;

/**
 * Utilities for dealing with dates and times
 */
public class TimeUtils {

    public static final List<Long> times = Arrays.asList(
        DAYS.toMillis(365),
        DAYS.toMillis(30),
        DAYS.toMillis(7),
        DAYS.toMillis(1),
        HOURS.toMillis(1),
        MINUTES.toMillis(1),
        SECONDS.toMillis(1)
    );

    public static final List<String> timesString = Arrays.asList(
        "yr", "mo", "wk", "day", "hr", "min", "sec"
    );

    /**
     * Get relative time ago for date
     *
     * NOTE:
     *  if (duration > WEEK_IN_MILLIS) getRelativeTimeSpanString prints the date.
     *
     * ALT:
     *  return getRelativeTimeSpanString(date, now, SECOND_IN_MILLIS, FORMAT_ABBREV_RELATIVE);
     *
     * @param date String.valueOf(TimeUtils.getRelativeTime(1000L * Date/Time in Millis)
     * @return relative time
     */
    public static CharSequence getRelativeTime(final long date) {
        return toDuration( Math.abs(System.currentTimeMillis() - date) );
    }

    private static String toDuration(long duration) {
        StringBuilder sb = new StringBuilder();
        for(int i=0;i< times.size(); i++) {
            Long current = times.get(i);
            long temp = duration / current;
            if (temp > 0) {
                sb.append(temp)
                  .append(" ")
                  .append(timesString.get(i))
                  .append(temp > 1 ? "s" : "")
                  .append(" ago");
                break;
            }
        }
        return sb.toString().isEmpty() ? "now" : sb.toString();
    }
}

答案 15 :(得分:2)

如果我们考虑性能,这是一个更好的代码。它减少了计算次数。 的原因 仅当秒数大于60时计算分钟,并且仅在分钟数大于60时计算小时数等等...

{{1}}

答案 16 :(得分:1)

SQL 时间戳到现在经过的时间。设置您自己的时区。

注意1:这将处理单数/复数。

注意2:这是使用Joda时间

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

答案 17 :(得分:1)

适用于Android 正如拉维所说的那样,但由于很多人都希望只是复制粘贴这就是它。

  try {
      SimpleDateFormat formatter = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss Z");
      Date dt = formatter.parse(date_from_server);
      CharSequence output = DateUtils.getRelativeTimeSpanString (dt.getTime());
      your_textview.setText(output.toString());
    } catch (Exception ex) {
      ex.printStackTrace();
      your_textview.setText("");
    }

有更多时间的人的说明

  1. 您从某处获取数据。首先,你必须弄清楚它的格式。
  2. 实施例。我从格式的服务器获取数据 2016年1月27日星期三09:32:35 GMT [这可能不是你的情况]

    这被翻译成

    SimpleDateFormat formatter = new SimpleDateFormat(“EEE,dd MMM yyyy HH:mm:ss Z”);

    我怎么知道呢?阅读documentation here.

    然后我解析它后得到约会。那个日期我放入了getRelativeTimeSpanString(没有任何额外的参数对我来说没问题,默认为几分钟)

    如果您没有找到正确的解析字符串,您将收到异常,例如:字符5处的异常 查看字符5,并更正初始解析字符串。。您可能会得到另一个例外,重复此步骤,直到您拥有正确的公式。

答案 18 :(得分:1)

private const val SECOND_MILLIS = 1
private const val MINUTE_MILLIS = 60 * SECOND_MILLIS
private const val HOUR_MILLIS = 60 * MINUTE_MILLIS
private const val DAY_MILLIS = 24 * HOUR_MILLIS

object TimeAgo {

fun timeAgo(time: Int): String {

    val now = TimeUnit.MILLISECONDS.toSeconds(System.currentTimeMillis())
    if (time > now || time <= 0) {
        return "in the future"
    }

    val diff = now - time
    return when {
        diff < MINUTE_MILLIS -> "Just now"
        diff < 2 * MINUTE_MILLIS -> "a minute ago"
        diff < 60 * MINUTE_MILLIS -> "${diff / MINUTE_MILLIS} minutes ago"
        diff < 2 * HOUR_MILLIS -> "an hour ago"
        diff < 24 * HOUR_MILLIS -> "${diff / HOUR_MILLIS} hours ago"
        diff < 48 * HOUR_MILLIS -> "yesterday"
        else -> "${diff / DAY_MILLIS} days ago"
    }
}

}

致电

val字符串= timeAgo(unixTimeStamp)

在科特林得到时间

答案 19 :(得分:1)

java.time

Answer by Habsq的想法正确但方法错误。

对于不附加到时间轴上的时间跨度,以年-月-日为单位,请使用Period。对于表示与日历和小时-分钟-秒无关的24小时时间段的天,请使用Duration。混合两个音阶几乎没有任何意义。

Duration

首先使用UTC类获取Instant中的当前时刻。

Instant now = Instant.now();  // Capture the current moment as seen in UTC.
Instant then = now.minus( 8L , ChronoUnit.HOURS ).minus( 8L , ChronoUnit.MINUTES ).minus( 8L , ChronoUnit.SECONDS );
Duration d = Duration.between( then , now );

生成小时,分钟和秒的文本。

// Generate text by calling `to…Part` methods.
String output = d.toHoursPart() + " hours ago\n" + d.toMinutesPart() + " minutes ago\n" + d.toSecondsPart() + " seconds ago";

转储到控制台。

System.out.println( "From: " + then + " to: " + now );
System.out.println( output );
  

从:2019-06-04T11:53:55.714965Z到:2019-06-04T20:02:03.714965Z

     

8小时前

     

8分钟前

     

8秒前

Period

从获取当前日期开始。

时区对于确定日期至关重要。在任何给定时刻,日期都会在全球范围内变化。例如,Paris France午夜之后的几分钟是新的一天,而Montréal Québec仍然是“昨天”。

如果未指定时区,则JVM隐式应用其当前的默认时区。该默认值可能在运行时(!)期间change at any moment,因此您的结果可能会有所不同。最好将您的期望/期望时区明确指定为参数。如果紧急,请与您的用户确认区域。

Continent/Region的格式指定proper time zone name,例如America/MontrealAfrica/CasablancaPacific/Auckland。切勿使用2-4个字母的缩写,例如ESTIST,因为它们不是真正的时区,不是标准化的,甚至不是唯一的(!)。

ZoneId z = ZoneId.of( "America/Montreal" ) ;  
LocalDate today = LocalDate.now( z ) ;

重新创建日期八天,几个月和几年前。

LocalDate then = today.minusYears( 8 ).minusMonths( 8 ).minusDays( 7 ); // Notice the 7 days, not 8, because of granularity of months. 

计算经过的时间。

Period p = Period.between( then , today );

构建“时间较早”片段的字符串。

String output = p.getDays() + " days ago\n" + p.getMonths() + " months ago\n" + p.getYears() + " years ago";

转储到控制台。

System.out.println( "From: " + then + " to: " + today );
System.out.println( output );
  

从:2010-09-27至:2019-06-04

     

8天前

     

8个月前

     

8年前


关于 java.time

java.time框架已内置在Java 8及更高版本中。这些类取代了麻烦的旧legacy日期时间类,例如java.util.DateCalendarSimpleDateFormat

要了解更多信息,请参见Oracle Tutorial。并在Stack Overflow中搜索许多示例和说明。规格为JSR 310

目前位于Joda-Timemaintenance mode项目建议迁移到java.time类。

您可以直接与数据库交换 java.time 对象。使用符合JDBC driver或更高版本的JDBC 4.2。不需要字符串,不需要java.sql.*类。

在哪里获取java.time类?

ThreeTen-Extra项目使用其他类扩展了java.time。该项目为将来可能在java.time中添加内容提供了一个试验场。您可能会在这里找到一些有用的类,例如IntervalYearWeekYearQuartermore

答案 20 :(得分:0)

为此,在此示例中,我已经完成了<link href="https://maxcdn.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css" rel="stylesheet"/> <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> <script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.1.3/js/bootstrap.min.js"></script> <button type="button" class="btn btn-primary" data-toggle="modal" data-target="#data1"> View </button> <p>If you don't want to download and host Bootstrap 4 yourself, you can include it from a CDN (Content Delivery Network). MaxCDN provides CDN support for Bootstrap's CSS and JavaScript. You must also include jQuery:If you don't want to download and host Bootstrap 4 yourself, you can include it from a CDN (Content Delivery Network). MaxCDN provides CDN support for Bootstrap's CSS and JavaScript. You must also include jQuery:If you don't want to download and host Bootstrap 4 yourself, you can include it from a CDN (Content Delivery Network). MaxCDN provides CDN support for Bootstrap's CSS and JavaScript. You must also include jQuery:If you don't want to download and host Bootstrap 4 yourself, you can include it from a CDN (Content Delivery Network). MaxCDN provides CDN support for Bootstrap's CSS and JavaScript. You must also include jQuery:If you don't want to download and host Bootstrap 4 yourself, you can include it from a CDN (Content Delivery Network). MaxCDN provides CDN support for Bootstrap's CSS and JavaScript. You must also include jQuery:If you don't want to download and host Bootstrap 4 yourself, you can include it from a CDN (Content Delivery Network). MaxCDN provides CDN support for Bootstrap's CSS and JavaScript. You must also include jQuery:If you don't want to download and host Bootstrap 4 yourself, you can include it from a CDN (Content Delivery Network). MaxCDN provides CDN support for Bootstrap's CSS and JavaScript. You must also include jQuery:If you don't want to download and host Bootstrap 4 yourself, you can include it from a CDN (Content Delivery Network). MaxCDN provides CDN support for Bootstrap's CSS and JavaScript. You must also include jQuery:If you don't want to download and host Bootstrap 4 yourself, you can include it from a CDN (Content Delivery Network). MaxCDN provides CDN support for Bootstrap's CSS and JavaScript. You must also include jQuery:If you don't want to download and host Bootstrap 4 yourself, you can include it from a CDN (Content Delivery Network). MaxCDN provides CDN support for Bootstrap's CSS and JavaScript. You must also include jQuery:If you don't want to download and host Bootstrap 4 yourself, you can include it from a CDN (Content Delivery Network). MaxCDN provides CDN support for Bootstrap's CSS and JavaScript. You must also include jQuery:If you don't want to download and host Bootstrap 4 yourself, you can include it from a CDN (Content Delivery Network). MaxCDN provides CDN support for Bootstrap's CSS and JavaScript. You must also include jQuery:If you don't want to download and host Bootstrap 4 yourself, you can include it from a CDN (Content Delivery Network). MaxCDN provides CDN support for Bootstrap's CSS and JavaScript. You must also include jQuery:</p> <div class="modal fade" id="data1" tabindex="-1" role="dialog" aria-labelledby="exampleModalLabel" aria-hidden="true"> <div class="modal-dialog" role="document"> <div class="modal-content"> <div class="modal-header"> <h3 class="modal-title title" id="exampleModalLabel">Trade Details</h3> <button type="button" class="close" data-dismiss="modal" aria-label="Close"> <span aria-hidden="true">&times;</span> </button> </div> <div class="modal-body"> <div class="card-body card-block"> <div class="displaydata"> <table class="table table-bordered"> <tbody> <tr> <th scope="col">S.N</th> <th scope="row">1</th> </tr> <tr> <th scope="col">Company</th> <th scope="row">Mark Company</th> </tr> </tbody> </table> </div> </div> </div> <div class="modal-footer"> <button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button> <button type="button" class="btn btn-primary approve" data-dismiss="modal" data-toggle="modal" data-target="#entry02">Approve </button> <input type="submit" class="btn btn-primary" value="Edit"> </div> </div> </div> </div> <div class="modal fade" id="entry02" tabindex="-1" role="dialog" aria-labelledby="exampleModalLabel" aria-hidden="true"> <div class="modal-dialog" role="document"> <div class="modal-content"> <div class="modal-header"> <h3 class="modal-title title" id="exampleModalLabel">Pre-Payments/LC's Report Detail</h3> <button type="button" class="close" data-dismiss="modal" aria-label="Close"> <span aria-hidden="true">&times;</span> </button> </div> <div class="modal-body"> <div class="card-body card-block"> <div class="displaydata"> <table class="table table-bordered"> <tbody> <tr> <th scope="col">Due Date</th> <th scope="row">21st August</th> </tr> <tr> <th scope="col">As per PI Cash/TT/Advance </th> <th scope="row">210</th> </tr> <tr> <th scope="col">Incoming/Outgoing LC Number/ Value</th> <th scope="row">20</th> </tr> <tr> <th scope="col">Company</th> <th scope="row">Mark Company</th> </tr> <tr> <th scope="col">Company</th> <th scope="row">Mark Company</th> </tr> <tr> <th scope="col">Company</th> <th scope="row">Mark Company</th> </tr> </tbody> </table> </div> </div> <div class="modal-footer"> <button type="button" class="btn btn-default btn-prev">Prev</button> <button type="button" class="btn btn-default btn-next">Next</button> <button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button> <input type="submit" class="btn btn-primary" value="Edit"> </div> </div> </div> </div> </div> <div class="modal fade" id="entry03" tabindex="-1" role="dialog" aria-labelledby="exampleModalLabel" aria-hidden="true"> <div class="modal-dialog" role="document"> <div class="modal-content"> <div class="modal-header"> <h3 class="modal-title title" id="exampleModalLabel">Sales and Purchase Report Detail</h3> <button type="button" class="close" data-dismiss="modal" aria-label="Close"> <span aria-hidden="true">&times;</span> </button> </div> <div class="modal-body"> <div class="card-body card-block"> <div class="displaydata"> <table class="table table-bordered"> <tbody> <tr> <th scope="col">Purchase/Sales Invoice Date</th> <th scope="row">1st October</th> </tr> </tbody> </table> </div> </div> <div class="modal-footer"> <button type="button" class="btn btn-default btn-prev">Prev</button> <button type="button" class="btn btn-default btn-next">Next</button> <button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button> <input type="submit" class="btn btn-primary" value="Edit"> </div> </div> </div> </div> </div>,您可以解析日期,例如Just Now, seconds ago, min ago, hrs ago, days ago, weeks ago, months ago, years ago,也可以解析以下任何其他日期

string.xml

中添加以下值
2018-09-05T06:40:46.183Z

java代码在下面尝试

  <string name="lbl_justnow">Just Now</string>
    <string name="lbl_seconds_ago">seconds ago</string>
    <string name="lbl_min_ago">min ago</string>
    <string name="lbl_mins_ago">mins ago</string>
    <string name="lbl_hr_ago">hr ago</string>
    <string name="lbl_hrs_ago">hrs ago</string>
    <string name="lbl_day_ago">day ago</string>
    <string name="lbl_days_ago">days ago</string>
    <string name="lbl_lstweek_ago">last week</string>
    <string name="lbl_week_ago">weeks ago</string>
    <string name="lbl_onemonth_ago">1 month ago</string>
    <string name="lbl_month_ago">months ago</string>
    <string name="lbl_oneyear_ago" >last year</string>
    <string name="lbl_year_ago" >years ago</string>

答案 21 :(得分:0)

您可以使用Java的库RelativeDateTimeFormatter,它正是这样做的:

RelativeDateTimeFormatter fmt = RelativeDateTimeFormatter.getInstance();
 fmt.format(1, Direction.NEXT, RelativeUnit.DAYS); // "in 1 day"
 fmt.format(3, Direction.NEXT, RelativeUnit.DAYS); // "in 3 days"
 fmt.format(3.2, Direction.LAST, RelativeUnit.YEARS); // "3.2 years ago"

 fmt.format(Direction.LAST, AbsoluteUnit.SUNDAY); // "last Sunday"
 fmt.format(Direction.THIS, AbsoluteUnit.SUNDAY); // "this Sunday"
 fmt.format(Direction.NEXT, AbsoluteUnit.SUNDAY); // "next Sunday"
 fmt.format(Direction.PLAIN, AbsoluteUnit.SUNDAY); // "Sunday"

 fmt.format(Direction.LAST, AbsoluteUnit.DAY); // "yesterday"
 fmt.format(Direction.THIS, AbsoluteUnit.DAY); // "today"
 fmt.format(Direction.NEXT, AbsoluteUnit.DAY); // "tomorrow"

 fmt.format(Direction.PLAIN, AbsoluteUnit.NOW); // "now"

答案 22 :(得分:0)

我正在使用Instant,Date和DateTimeUtils。 数据(日期)以String类型存储在数据库中,然后转换为Instant。

    /*
    This method is to display ago.
    Example: 3 minutes ago.
    I already implement the latest which is including the Instant.
    Convert from String to Instant and then parse to Date.
     */
    public String convertTimeToAgo(String dataDate) {
    //Initialize
    String conversionTime = null;
    String suffix = "Yang Lalu";
    Date pastTime;
    //Parse from String (which is stored as Instant.now().toString()
    //And then convert to become Date
    Instant instant = Instant.parse(dataDate);
    pastTime = DateTimeUtils.toDate(instant);

    //Today date
    Date nowTime = new Date();

    long dateDiff = nowTime.getTime() - pastTime.getTime();
    long second = TimeUnit.MILLISECONDS.toSeconds(dateDiff);
    long minute = TimeUnit.MILLISECONDS.toMinutes(dateDiff);
    long hour = TimeUnit.MILLISECONDS.toHours(dateDiff);
    long day = TimeUnit.MILLISECONDS.toDays(dateDiff);

    if (second < 60) {
        conversionTime = second + " Saat " + suffix;
    } else if (minute < 60) {
        conversionTime = minute + " Minit " + suffix;
    } else if (hour < 24) {
        conversionTime = hour + " Jam " + suffix;
    } else if (day >= 7) {
        if (day > 30) {
            conversionTime = (day / 30) + " Bulan " + suffix;
        } else if (day > 360) {
            conversionTime = (day / 360) + " Tahun " + suffix;
        } else {
            conversionTime = (day / 7) + " Minggu " + suffix;
        }
    } else if (day < 7) {
        conversionTime = day + " Hari " + suffix;
    }
    return conversionTime;
    }

答案 23 :(得分:0)

这是非常基本的脚本。它易于改进。
结果:(XXX小时前),或(XX天前/昨天/今天)

jointRemapList

答案 24 :(得分:0)

以下解决方案全部使用纯Java:

选项1:不进行取整,仅使用最大的时间容器

以下功能将仅显示最大的时间容器,例如,如果实际经过时间为"1 month 14 days ago",则此功能将仅显示"1 month ago"。此功能还将始终取整,因此等于"50 days ago"的时间将显示为"1 month"

public String formatTimeAgo(long millis) {
        String[] ids = new String[]{"second","minute","hour","day","month","year"};

        long seconds = millis / 1000;
        long minutes = seconds / 60;
        long hours = minutes / 60;
        long days = hours / 24;
        long months = days / 30;
        long years = months / 12;

        ArrayList<Long> times = new ArrayList<>(Arrays.asList(years, months, days, hours, minutes, seconds));

        for(int i = 0; i < times.size(); i++) {
            if(times.get(i) != 0) {
                long value = times.get(i).intValue();

                return value + " " + ids[ids.length - 1 - i] + (value == 1 ? "" : "s") + " ago";
            }
        }

        return "0 seconds ago";
    }

选项2:四舍五入

只需使用Math.round(...)语句包装要舍入的时间容器,因此,如果要将50 days舍入为2 months,请修改long months = days / 30long months = Math.round(days / 30.0)

答案 25 :(得分:0)

这是我的测试用例,希望对您有帮助:

    val currentCalendar = Calendar.getInstance()
    currentCalendar.set(2019, 6, 2, 5, 31, 0)

    val targetCalendar = Calendar.getInstance()
    targetCalendar.set(2019, 6, 2, 5, 30, 0)

    val diffTs = currentCalendar.timeInMillis - targetCalendar.timeInMillis
    val diffMins = TimeUnit.MILLISECONDS.toMinutes(diffTs)
    val diffHours = TimeUnit.MILLISECONDS.toHours(diffTs)
    val diffDays = TimeUnit.MILLISECONDS.toDays(diffTs)
    val diffWeeks = TimeUnit.MILLISECONDS.toDays(diffTs) / 7
    val diffMonths = TimeUnit.MILLISECONDS.toDays(diffTs) / 30
    val diffYears = TimeUnit.MILLISECONDS.toDays(diffTs) / 365

    val newTs = when {
        diffYears >= 1 -> "Years $diffYears"
        diffMonths >= 1 -> "Months $diffMonths"
        diffWeeks >= 1 -> "Weeks $diffWeeks"
        diffDays >= 1 -> "Days $diffDays"
        diffHours >= 1 -> "Hours $diffHours"
        diffMins >= 1 -> "Mins $diffMins"
        else -> "now"
    }

答案 26 :(得分:0)

它对我有用

public class TimeDifference {
    int years;
    int months;
    int days;
    int hours;
    int minutes;
    int seconds;
    String differenceString;

    public TimeDifference(@NonNull Date curdate, @NonNull Date olddate) {

        float diff = curdate.getTime() - olddate.getTime();
        if (diff >= 0) {
            int yearDiff = Math.round((diff / (AppConstant.aLong * AppConstant.aFloat)) >= 1 ? (diff / (AppConstant.aLong * AppConstant.aFloat)) : 0);
            if (yearDiff > 0) {
                years = yearDiff;
                setDifferenceString(years + (years == 1 ? " year" : " years") + " ago");
            } else {
                int monthDiff = Math.round((diff / AppConstant.aFloat) >= 1 ? (diff / AppConstant.aFloat) : 0);
                if (monthDiff > 0) {
                    if (monthDiff > AppConstant.ELEVEN) {
                        monthDiff = AppConstant.ELEVEN;
                    }
                    months = monthDiff;
                    setDifferenceString(months + (months == 1 ? " month" : " months") + " ago");
                } else {
                    int dayDiff = Math.round((diff / (AppConstant.bFloat)) >= 1 ? (diff / (AppConstant.bFloat)) : 0);
                    if (dayDiff > 0) {
                        days = dayDiff;
                        if (days == AppConstant.THIRTY) {
                            days = AppConstant.TWENTYNINE;
                        }
                        setDifferenceString(days + (days == 1 ? " day" : " days") + " ago");
                    } else {
                        int hourDiff = Math.round((diff / (AppConstant.cFloat)) >= 1 ? (diff / (AppConstant.cFloat)) : 0);
                        if (hourDiff > 0) {
                            hours = hourDiff;
                            setDifferenceString(hours + (hours == 1 ? " hour" : " hours") + " ago");
                        } else {
                            int minuteDiff = Math.round((diff / (AppConstant.dFloat)) >= 1 ? (diff / (AppConstant.dFloat)) : 0);
                            if (minuteDiff > 0) {
                                minutes = minuteDiff;
                                setDifferenceString(minutes + (minutes == 1 ? " minute" : " minutes") + " ago");
                            } else {
                                int secondDiff = Math.round((diff / (AppConstant.eFloat)) >= 1 ? (diff / (AppConstant.eFloat)) : 0);
                                if (secondDiff > 0) {
                                    seconds = secondDiff;
                                } else {
                                    seconds = 1;
                                }
                                setDifferenceString(seconds + (seconds == 1 ? " second" : " seconds") + " ago");
                            }
                        }
                    }

                }
            }

        } else {
            setDifferenceString("Just now");
        }

    }

    public String getDifferenceString() {
        return differenceString;
    }

    public void setDifferenceString(String differenceString) {
        this.differenceString = differenceString;
    }

    public int getYears() {
        return years;
    }

    public void setYears(int years) {
        this.years = years;
    }

    public int getMonths() {
        return months;
    }

    public void setMonths(int months) {
        this.months = months;
    }

    public int getDays() {
        return days;
    }

    public void setDays(int days) {
        this.days = days;
    }

    public int getHours() {
        return hours;
    }

    public void setHours(int hours) {
        this.hours = hours;
    }

    public int getMinutes() {
        return minutes;
    }

    public void setMinutes(int minutes) {
        this.minutes = minutes;
    }

    public int getSeconds() {
        return seconds;
    }

    public void setSeconds(int seconds) {
        this.seconds = seconds;
    } }

答案 27 :(得分:0)

getrelativeDateTime 函数将为您提供日期时间,就像您在Whatsapp通知中看到的一样。
要获取将来的相对日期时间,请为其添加条件。这是专门为获取日期时间(如Whatsapp通知)而创建的。

private static String getRelativeDateTime(long date) {
    SimpleDateFormat DateFormat = new SimpleDateFormat("MMM dd, yyyy", Locale.getDefault());
    SimpleDateFormat TimeFormat = new SimpleDateFormat(" hh:mm a", Locale.getDefault());
    long now = Calendar.getInstance().getTimeInMillis();
    long startOfDay = StartOfDay(Calendar.getInstance().getTime());
    String Day = "";
    String Time = "";
    long millSecInADay = 86400000;
    long oneHour = millSecInADay / 24;
    long differenceFromNow = now - date;

    if (date > startOfDay) {
        if (differenceFromNow < (oneHour)) {
            int minute = (int) (differenceFromNow / (60000));
            if (minute == 0) {
                int sec = (int) differenceFromNow / 1000;
                if (sec == 0) {
                    Time = "Just Now";
                } else if (sec == 1) {
                    Time = sec + " second ago";
                } else {
                    Time = sec + " seconds ago";
                }
            } else if (minute == 1) {
                Time = minute + " minute ago";
            } else if (minute < 60) {
                Time = minute + " minutes ago";
            }
        } else {
            Day = "Today, ";
        }
    } else if (date > (startOfDay - millSecInADay)) {
        Day = "Yesterday, ";
    } else if (date > (startOfDay - millSecInADay * 7)) {
        int days = (int) (differenceFromNow / millSecInADay);
        Day = days + " Days ago, ";
    } else {
        Day = DateFormat.format(date);
    }
    if (Time.isEmpty()) {
        Time = TimeFormat.format(date);
    }
    return Day + Time;
}

public static long StartOfDay(Date date) {
    Calendar calendar = Calendar.getInstance();
    calendar.setTime(date);
    calendar.set(Calendar.HOUR_OF_DAY, 0);
    calendar.set(Calendar.MINUTE, 0);
    calendar.set(Calendar.SECOND, 0);
    calendar.set(Calendar.MILLISECOND, 0);
    return calendar.getTimeInMillis();
}

答案 28 :(得分:0)

由于缺乏简洁性和更新的响应,请遵循更新的Java 8及更高版本

import java.time.*;
import java.time.temporal.*;

public class Time {
    public static void main(String[] args) {

        System.out.println(LocalTime.now().minus(8, ChronoUnit.MINUTES));
        System.out.println(LocalTime.now().minus(8, ChronoUnit.HOURS));
        System.out.println(LocalDateTime.now().minus(8, ChronoUnit.DAYS));
        System.out.println(LocalDateTime.now().minus(8, ChronoUnit.MONTHS));
    }
}

这是使用Java Time API的版本,该版本试图解决过去处理日期和时间的问题。

Javadoc

版本8 https://docs.oracle.com/javase/8/docs/api/index.html?java/time/package-summary.html

版本11 https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/time/package-summary.html

W3Schools教程-https://www.w3schools.com/java/java_date.asp

DZone文章-https://dzone.com/articles/java-8-date-and-time

答案 29 :(得分:0)

这是我的

的Java实现
    public static String relativeDate(Date date){
    Date now=new Date();
    if(date.before(now)){
    int days_passed=(int) TimeUnit.MILLISECONDS.toDays(now.getTime() - date.getTime());
    if(days_passed>1)return days_passed+" days ago";
    else{
        int hours_passed=(int) TimeUnit.MILLISECONDS.toHours(now.getTime() - date.getTime());
        if(hours_passed>1)return days_passed+" hours ago";
        else{
            int minutes_passed=(int) TimeUnit.MILLISECONDS.toMinutes(now.getTime() - date.getTime());
            if(minutes_passed>1)return minutes_passed+" minutes ago";
            else{
                int seconds_passed=(int) TimeUnit.MILLISECONDS.toSeconds(now.getTime() - date.getTime());
                return seconds_passed +" seconds ago";
            }
        }
    }

    }
    else
    {
        return new SimpleDateFormat("HH:mm:ss MM/dd/yyyy").format(date).toString();
    }
  }

答案 30 :(得分:0)

java.time

您可以使用 java.time.Durationjava.time.Period,它们以 ISO-8601 standards 为模型并作为 JSR-310 implementation 的一部分与 Java-8 一起引入。 Java-9 引入了一些更方便的方法。

  1. 使用 Duration 计算基于时间的数量或时间量。可以使用基于持续时间的单位访问它,例如纳秒、秒、分钟和小时。此外,可以使用 DAYS 单位并将其视为完全等于 24 小时,从而忽略夏令时的影响。
  2. 使用 Period 计算基于日期的时间量。可以使用基于周期的单位(例如天、月和年)访问它。

演示:

import java.time.Duration;
import java.time.LocalDateTime;
import java.time.Month;

public class Main {
    public static void main(String[] args) {
        // An arbitrary local date and time
        LocalDateTime startDateTime = LocalDateTime.of(2020, Month.DECEMBER, 10, 15, 20, 25);

        // Current local date and time
        LocalDateTime endDateTime = LocalDateTime.now();

        Duration duration = Duration.between(startDateTime, endDateTime);
        // Default format
        System.out.println(duration);

        // Custom format
        // ####################################Java-8####################################
        String formattedElapsedTime = String.format("%d days, %d hours, %d minutes, %d seconds, %d nanoseconds ago",
                duration.toDays(), duration.toHours() % 24, duration.toMinutes() % 60, duration.toSeconds() % 60,
                duration.toNanos() % 1000000000);
        System.out.println(formattedElapsedTime);
        // ##############################################################################

        // ####################################Java-9####################################
        formattedElapsedTime = String.format("%d days, %d hours, %d minutes, %d seconds, %d nanoseconds ago",
                duration.toDaysPart(), duration.toHoursPart(), duration.toMinutesPart(), duration.toSecondsPart(),
                duration.toNanosPart());
        System.out.println(formattedElapsedTime);
        // ##############################################################################
    }
}

输出:

PT1395H35M7.355288S
58 days, 3 hours, 35 minutes, 7 seconds, 355288000 nanoseconds ago
58 days, 3 hours, 35 minutes, 7 seconds, 355288000 nanoseconds ago

如果您在 UTC 有两个时刻,您可以使用 Instant 代替 LocalDateTime 例如

import java.time.Duration;
import java.time.Instant;
import java.time.temporal.ChronoUnit;

public class Main {
    public static void main(String[] args) {
        // Current moment at UTC
        Instant now = Instant.now();

        // An instant in the past
        Instant startDateTime = now.minus(58, ChronoUnit.DAYS)
                                .minus(2, ChronoUnit.HOURS)
                                .minus(54, ChronoUnit.MINUTES)
                                .minus(24, ChronoUnit.SECONDS)
                                .minus(808624000, ChronoUnit.NANOS);

        Duration duration = Duration.between(startDateTime, now);
        // Default format
        System.out.println(duration);

        // Custom format
        // ####################################Java-8####################################
        String formattedElapsedTime = String.format("%d days, %d hours, %d minutes, %d seconds, %d nanoseconds ago",
                duration.toDays(), duration.toHours() % 24, duration.toMinutes() % 60, duration.toSeconds() % 60,
                duration.toNanos() % 1000000000);
        System.out.println(formattedElapsedTime);
        // ##############################################################################

        // ####################################Java-9####################################
        formattedElapsedTime = String.format("%d days, %d hours, %d minutes, %d seconds, %d nanoseconds ago",
                duration.toDaysPart(), duration.toHoursPart(), duration.toMinutesPart(), duration.toSecondsPart(),
                duration.toNanosPart());
        System.out.println(formattedElapsedTime);
        // ##############################################################################
    }
}

输出:

PT1394H54M24.808624S
58 days, 2 hours, 54 minutes, 24 seconds, 808624000 nanoseconds ago
58 days, 2 hours, 54 minutes, 24 seconds, 808624000 nanoseconds ago

Period 上的演示:

import java.time.LocalDate;
import java.time.Period;
import java.time.ZoneId;

public class Main {
    public static void main(String[] args) {
        // Replace ZoneId.systemDefault() with the applicable timezone ID e.g.
        // ZoneId.of("Europe/London"). For LocalDate in the JVM's timezone, simply use
        // LocalDate.now()
        LocalDate endDate = LocalDate.now(ZoneId.systemDefault());

        // Let's assume the start date is 1 year, 2 months, and 3 days ago
        LocalDate startDate = endDate.minusYears(1).minusMonths(2).minusDays(3);

        Period period = Period.between(startDate, endDate);
        // Default format
        System.out.println(period);

        // Custom format
        String formattedElapsedPeriod = String.format("%d years, %d months, %d days ago", period.getYears(),
                period.getMonths(), period.getDays());
        System.out.println(formattedElapsedPeriod);
    }
}

输出:

P1Y2M3D
1 years, 2 months, 3 days ago

Trail: Date Time 了解现代日期时间 API。