【问题标题】:How to calculate elapsed time from now with Joda-Time?如何使用 Joda-Time 计算从现在开始经过的时间?
【发布时间】:2011-01-11 21:16:32
【问题描述】:

我需要计算从一个特定日期到现在所经过的时间,并以与 StackOverflow 问题相同的格式显示,即:

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

您知道如何使用 Java Joda-Time 来实现它吗?是否有已经实现它的辅助方法,还是我应该自己编写算法?

【问题讨论】:

  • “2008 年 12 月 25 日”不是“从一个特定日期到现在所经过的时间”(你用粗体写了;)
  • 我知道。但是 SO 正在显示这样的提问时间。如果时间段足够长,则会显示确切的日期。
  • 我对 StackOverflow 处理日期的方式很不满意。一开始你会得到非常精确的数字(37 秒前),但很快就会变得非常模糊(2 天前)。只有在时间以绝对格式显示后,您才能再次看到精确的(至少到分钟)日期和时间。我相信这种相对信息只是在绝对信息之外才有用,而不能代替它。
  • 您可以在工具提示中获取确切的日期时间。只需将日期时间悬停一会儿:)
  • Joda-Time 不适用于在需要额外功能时打印相对(经过)时间。接受的答案是可以的,但不可本地化(仅适用于英语)。如果您需要本地化支持,那么有更好的 3rd-party 库。 ocpsoft/PrettyTime 是一个更好的选择,但仅适用于旧类java.util.Date。但是,我的库 Time4J 是恕我直言,用于打印相对时间(前格式)或时间格式(如“3 个月,4 天”)的最佳库。它实际上也可以本地化为 72 种语言。

标签: java algorithm datetime grails jodatime


【解决方案1】:

要使用 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 秒前 51 分钟前 7 小时前 6 天前 10 个月前 31年前

(咳嗽,老,咳嗽) 您会看到,我也考虑了几个月和几年,并将其配置为在这些值为零时忽略这些值。

【讨论】:

  • 谢谢。我用你的代码作为我算法的基础。我基本上用 1 个字段(或最多 2 个字段)显示经过的时间。如果有人对代码感兴趣,我可以在这里发布它作为答案。它也符合 i18 标准。
  • 我用上面的代码进行了测试,发现格式化程序缺少周字段 - 天在第 6 天之后换行。所以我添加了:.appendWeeks().appendSuffix("weeks ago\n")
  • @fabien7474 你是如何调整它以只显示一个字段的?请务必将其发布为答案。
  • @fabien7474 你是怎么调整它只显示一个字段的?
  • 检查gist 只显示一个字段。
【解决方案2】:

使用PrettyTime 表示简单的经过时间。

我尝试HumanTime @sfussenegger 回答并使用 JodaTime 的 Period 但我发现的人类可读经过时间的最简单和最干净的方法是 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"

注意:我已经尝试过使用该库更精确的功能,但它会产生一些奇怪的结果,因此请小心使用它,不要危及生命的项目。

日本

【讨论】:

    【解决方案3】:

    您可以使用 PeriodFormatter 执行此操作,但您不必像 other answers 那样努力制作自己的 PeriodFormatBuilder。如果适合您的情况,您可以使用默认格式化程序:

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

    (在类似问题上向this answer 提示,我正在交叉发布以方便发现)

    【讨论】:

    • 我刚试过这个,它可以将所有字段的时间段细分到毫秒,所以 getDefault() 没有那么有用。
    • 我刚试过这个,它可以将所有字段的周期细分到毫秒,所以 getDefault() 很有帮助。 (感谢@snappieT)
    • 这对于大多数用例来说已经足够简洁了。
    【解决方案4】:

    有一个名为HumanTime 的小助手类,我很满意。

    【讨论】:

    • 这很棒。在您的答案中添加一个简单的输入和输出示例将非常有帮助。
    【解决方案5】:

    这是使用 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;
    } 
    

    【讨论】:

      【解决方案6】:

      这是我的解决方案,使用 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);
      

      【讨论】:

        猜你喜欢
        • 2011-06-26
        • 1970-01-01
        • 2013-07-04
        • 1970-01-01
        • 2016-05-30
        • 1970-01-01
        • 1970-01-01
        • 2011-10-14
        • 2014-03-07
        相关资源
        最近更新 更多