【问题标题】:How to format a duration in java? (e.g format H:MM:SS)如何在java中格式化持续时间? (例如格式 H:MM:SS)
【发布时间】:2010-09-20 23:26:55
【问题描述】:

我想使用 H:MM:SS 之类的模式来格式化持续时间(以秒为单位)。 Java 中的当前实用程序旨在格式化时间而不是持续时间。

【问题讨论】:

    标签: java date-formatting duration


    【解决方案1】:

    如果您不想拖入库,使用 Formatter 或相关快捷方式(例如。给定整数秒数:

      String.format("%d:%02d:%02d", s / 3600, (s % 3600) / 60, (s % 60));
    

    【讨论】:

    • 不一定是整数。如果您有两个日期,只需将 date1.getTime() - date2.getTime() 插入上述使用 long 原语的等式中,并且仍然有效。
    • 时差超过24小时怎么办?
    • @Rajish:在这种情况下,您必须询问 OP 他们想要什么!当然,如有必要,您可以将其分成 s/86400, (s%86400)/3600... 数天...
    • 我对@9​​87654323@0 的解决方案(一天):"\u221E" - infinity
    • 如果时差超过 24 小时,它仍然可以很好地格式化以小时、分钟和秒为单位的持续时间。对于我的用例,这符合预期。
    【解决方案2】:

    我像这样使用 Apache common 的 DurationFormatUtils

    DurationFormatUtils.formatDuration(millis, "**H:mm:ss**", true);
    

    【讨论】:

    • 最简单的方法(在 apache commons 风格中)。你甚至有 formatDurationHMS 方法,你可能会在大部分时间使用。
    • 完美!您还可以在撇号中添加其他文本: DurationFormatUtils.formatDuration(durationInMillis, "m 'minutes' , s 'seconds'")
    【解决方案3】:

    如果您使用的是 Java 8 之前的版本...您可以使用 Joda TimePeriodFormatter。如果您确实有一个持续时间(即经过的时间,不参考日历系统),那么您可能应该在大多数情况下使用Duration - 然后您可以调用toPeriod(指定任何@987654326 @您想反映 25 小时是否变为 1 天和 1 小时等)以获取您可以格式化的 Period

    如果您使用的是 Java 8 或更高版本:我通常建议使用 java.time.Duration 来表示持续时间。然后,您可以根据 bobince 的回答调用getSeconds() 或类似方法来获取标准字符串格式的整数(如果需要) - 尽管您应该小心持续时间为负数的情况,因为您可能想要一个 single 输出字符串中的负号。所以像:

    public static String formatDuration(Duration duration) {
        long seconds = duration.getSeconds();
        long absSeconds = Math.abs(seconds);
        String positive = String.format(
            "%d:%02d:%02d",
            absSeconds / 3600,
            (absSeconds % 3600) / 60,
            absSeconds % 60);
        return seconds < 0 ? "-" + positive : positive;
    }
    

    以这种方式进行格式化合理很简单,虽然很烦人。对于解析来说,这通常会变得更难……当然,即使使用 Java 8,你仍然可以使用 Joda Time。

    【讨论】:

    • 在使用 Java 8 时,您还推荐使用 Joda Time 库吗?
    • @TimBüthe:不,在这种情况下我会开始使用 java.time。 (虽然我不能立即找到 PeriodFormatter 的等价物......)
    • PeriodFormatter 不包括在内。这是 Java 8 Date Time API 和 Joda Time 之间的区别之一。
    • @RexKerr:当然,如果您愿意,仍然可以“使用 Joda Time”。将再次编辑。 (回想起来,无论如何我都应该推荐 Duration 的声音。需要大量编辑......)
    • @MarkJeronimus 更简单的方法是使用Durations 方法:duration.toHours()duration.toMinutesPart()duration.toSecondsPart(),它们从 Java 9 开始就可用。并且要获得可以使用的绝对值duration.abs().
    【解决方案4】:

    这从 Java 9 开始变得更容易了。Duration 仍然不可格式化,但添加了获取小时、分钟和秒的方法,这使得任务更加简单:

        LocalDateTime start = LocalDateTime.of(2019, Month.JANUARY, 17, 15, 24, 12);
        LocalDateTime end = LocalDateTime.of(2019, Month.JANUARY, 18, 15, 43, 33);
        Duration diff = Duration.between(start, end);
        String hms = String.format("%d:%02d:%02d", 
                                    diff.toHours(), 
                                    diff.toMinutesPart(), 
                                    diff.toSecondsPart());
        System.out.println(hms);
    

    这个 sn-p 的输出是:

    24:19:21

    【讨论】:

      【解决方案5】:
      long duration = 4 * 60 * 60 * 1000;
      SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss.SSS", Locale.getDefault());
      log.info("Duration: " + sdf.format(new Date(duration - TimeZone.getDefault().getRawOffset())));
      

      【讨论】:

      • 哈!使用此方法时,只需使用时区规范化即可。在使用format 函数之前,您必须添加sdf.setTimeZone(TimeZone.getTimeZone("GMT+0"));
      • 建议使用DateFormat.getDateInstance()而不是具体类。
      • 这个解决方案很脆弱。当小时数达到 24 小时时,它将滚动到 00:00:00.000。此外,负一秒的格式为23:59:59.000
      【解决方案6】:

      有一个相当简单和(IMO)优雅的方法,至少持续时间少于 24 小时:

      DateTimeFormatter.ISO_LOCAL_TIME.format(value.addTo(LocalTime.of(0, 0)))

      格式化程序需要一个时间对象来格式化,因此您可以通过将持续时间添加到 00:00(即午夜)的 LocalTime 来创建一个。这将为您提供一个 LocalTime 表示从午夜到该时间的持续时间,然后很容易以标准 HH:mm:ss 表示法格式化。这样做的好处是不需要外部库,使用java.time库进行计算,而不是手动计算时分秒。

      【讨论】:

      • 好把戏,。对于超过 24 小时的时间段,这将为您提供 24 小时的剩余时间,这不是我所需要的,但我同意这是迄今为止最优雅的。尽管如此,我还是对 java 8 的 Duration 对象没有一些内置的格式化工具感到相当失望。
      【解决方案7】:

      此答案仅使用 Duration 方法并适用于 Java 8:

      public static String format(Duration d) {
          long days = d.toDays();
          d = d.minusDays(days);
          long hours = d.toHours();
          d = d.minusHours(hours);
          long minutes = d.toMinutes();
          d = d.minusMinutes(minutes);
          long seconds = d.getSeconds() ;
          return 
                  (days ==  0?"":days+" jours,")+ 
                  (hours == 0?"":hours+" heures,")+ 
                  (minutes ==  0?"":minutes+" minutes,")+ 
                  (seconds == 0?"":seconds+" secondes,");
      }
      

      【讨论】:

        【解决方案8】:

        这可能有点 hacky,但如果一个人一心想使用 Java 8 的java.time 来完成此任务,这是一个很好的解决方案:

        import java.time.Duration;
        import java.time.LocalDateTime;
        import java.time.format.DateTimeFormatter;
        import java.time.format.DateTimeFormatterBuilder;
        import java.time.temporal.ChronoField;
        import java.time.temporal.Temporal;
        import java.time.temporal.TemporalAccessor;
        import java.time.temporal.TemporalField;
        import java.time.temporal.UnsupportedTemporalTypeException;
        
        public class TemporalDuration implements TemporalAccessor {
            private static final Temporal BASE_TEMPORAL = LocalDateTime.of(0, 1, 1, 0, 0);
        
            private final Duration duration;
            private final Temporal temporal;
        
            public TemporalDuration(Duration duration) {
                this.duration = duration;
                this.temporal = duration.addTo(BASE_TEMPORAL);
            }
        
            @Override
            public boolean isSupported(TemporalField field) {
                if(!temporal.isSupported(field)) return false;
                long value = temporal.getLong(field)-BASE_TEMPORAL.getLong(field);
                return value!=0L;
            }
        
            @Override
            public long getLong(TemporalField field) {
                if(!isSupported(field)) throw new UnsupportedTemporalTypeException(new StringBuilder().append(field.toString()).toString());
                return temporal.getLong(field)-BASE_TEMPORAL.getLong(field);
            }
        
            public Duration getDuration() {
                return duration;
            }
        
            @Override
            public String toString() {
                return dtf.format(this);
            }
        
            private static final DateTimeFormatter dtf = new DateTimeFormatterBuilder()
                    .optionalStart()//second
                    .optionalStart()//minute
                    .optionalStart()//hour
                    .optionalStart()//day
                    .optionalStart()//month
                    .optionalStart()//year
                    .appendValue(ChronoField.YEAR).appendLiteral(" Years ").optionalEnd()
                    .appendValue(ChronoField.MONTH_OF_YEAR).appendLiteral(" Months ").optionalEnd()
                    .appendValue(ChronoField.DAY_OF_MONTH).appendLiteral(" Days ").optionalEnd()
                    .appendValue(ChronoField.HOUR_OF_DAY).appendLiteral(" Hours ").optionalEnd()
                    .appendValue(ChronoField.MINUTE_OF_HOUR).appendLiteral(" Minutes ").optionalEnd()
                    .appendValue(ChronoField.SECOND_OF_MINUTE).appendLiteral(" Seconds").optionalEnd()
                    .toFormatter();
        
        }
        

        【讨论】:

        • 我刚试过这个,我注意到如果我在 没有 有任何小时或分钟来格式化时调用“hh:mm:ss”的格式(例如 @987654323 @),然后我会得到一个UnsupportedTemporalTypeException)。我只是删除了检查差异是否为== 01 的代码。我认为01 是某种我不完全理解的掩码值,你能解释一下吗?
        • 这实际上工作得很好。在我的情况下,我什至添加了毫秒......关于isSupported 方法,如果在人类可读的字符串上显示有效字段,它会返回信息。无论如何,“掩饰”实际上不是面具。代码显示return value!=0l 而不是return value!=01。下次请务必使用复制粘贴。
        • 接口TemporalAccessor 不应该在持续时间内被滥用。 JSR-310 为此设计了接口TemporalAmount
        • 我建议您始终使用大写的 L 来表示 long 值。正如刚才演示的那样,很容易将小写 l 误读为数字 1。
        【解决方案9】:

        我不确定这是你想要的,但请检查这个 Android 帮助程序类

        import android.text.format.DateUtils
        

        例如:DateUtils.formatElapsedTime()

        【讨论】:

          【解决方案10】:

          这里是另一个如何格式化持续时间的示例。 请注意,此示例将正持续时间和负持续时间都显示为正持续时间。

          import static java.time.temporal.ChronoUnit.DAYS;
          import static java.time.temporal.ChronoUnit.HOURS;
          import static java.time.temporal.ChronoUnit.MINUTES;
          import static java.time.temporal.ChronoUnit.SECONDS;
          
          import java.time.Duration;
          
          public class DurationSample {
              public static void main(String[] args) {
                  //Let's say duration of 2days 3hours 12minutes and 46seconds
                  Duration d = Duration.ZERO.plus(2, DAYS).plus(3, HOURS).plus(12, MINUTES).plus(46, SECONDS);
          
                  //in case of negative duration
                  if(d.isNegative()) d = d.negated();
          
                  //format DAYS HOURS MINUTES SECONDS 
                  System.out.printf("Total duration is %sdays %shrs %smin %ssec.\n", d.toDays(), d.toHours() % 24, d.toMinutes() % 60, d.getSeconds() % 60);
          
                  //or format HOURS MINUTES SECONDS 
                  System.out.printf("Or total duration is %shrs %smin %sec.\n", d.toHours(), d.toMinutes() % 60, d.getSeconds() % 60);
          
                  //or format MINUTES SECONDS 
                  System.out.printf("Or total duration is %smin %ssec.\n", d.toMinutes(), d.getSeconds() % 60);
          
                  //or format SECONDS only 
                  System.out.printf("Or total duration is %ssec.\n", d.getSeconds());
              }
          }
          

          【讨论】:

            【解决方案11】:

            下面的函数怎么样,它返回 +H:MM:SS 要么 +H:MM:SS.sss

            public static String formatInterval(final long interval, boolean millisecs )
            {
                final long hr = TimeUnit.MILLISECONDS.toHours(interval);
                final long min = TimeUnit.MILLISECONDS.toMinutes(interval) %60;
                final long sec = TimeUnit.MILLISECONDS.toSeconds(interval) %60;
                final long ms = TimeUnit.MILLISECONDS.toMillis(interval) %1000;
                if( millisecs ) {
                    return String.format("%02d:%02d:%02d.%03d", hr, min, sec, ms);
                } else {
                    return String.format("%02d:%02d:%02d", hr, min, sec );
                }
            }
            

            【讨论】:

              【解决方案12】:

              这是一个可行的选择。

              public static String showDuration(LocalTime otherTime){          
                  DateTimeFormatter df = DateTimeFormatter.ISO_LOCAL_TIME;
                  LocalTime now = LocalTime.now();
                  System.out.println("now: " + now);
                  System.out.println("otherTime: " + otherTime);
                  System.out.println("otherTime: " + otherTime.format(df));
              
                  Duration span = Duration.between(otherTime, now);
                  LocalTime fTime = LocalTime.ofNanoOfDay(span.toNanos());
                  String output = fTime.format(df);
              
                  System.out.println(output);
                  return output;
              }
              

              调用方法

              System.out.println(showDuration(LocalTime.of(9, 30, 0, 0)));
              

              产生类似的东西:

              otherTime: 09:30
              otherTime: 09:30:00
              11:31:27.463
              11:31:27.463
              

              【讨论】:

              • 如果持续时间超过 23:59:59.999,这将失败。
              【解决方案13】:

              您可以使用java.time.Duration,它以ISO-8601 standards 为蓝本,并作为JSR-310 implementation 的一部分引入Java-8Java-9 引入了一些更方便的方法。

              演示:

              import java.time.Duration;
              import java.time.LocalDateTime;
              import java.time.Month;
              
              public class Main {
                  public static void main(String[] args) {
                      LocalDateTime startDateTime = LocalDateTime.of(2020, Month.DECEMBER, 10, 15, 20, 25);
                      LocalDateTime endDateTime = LocalDateTime.of(2020, Month.DECEMBER, 10, 18, 24, 30);
              
                      Duration duration = Duration.between(startDateTime, endDateTime);
                      // Default format
                      System.out.println(duration);
              
                      // Custom format
                      // ####################################Java-8####################################
                      String formattedElapsedTime = String.format("%02d:%02d:%02d", duration.toHours() % 24,
                              duration.toMinutes() % 60, duration.toSeconds() % 60);
                      System.out.println(formattedElapsedTime);
                      // ##############################################################################
              
                      // ####################################Java-9####################################
                      formattedElapsedTime = String.format("%02d:%02d:%02d", duration.toHoursPart(), duration.toMinutesPart(),
                              duration.toSecondsPart());
                      System.out.println(formattedElapsedTime);
                      // ##############################################################################
                  }
              }
              

              输出:

              PT3H4M5S
              03:04:05
              03:04:05
              

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

              【讨论】:

                【解决方案14】:

                还有另一种方法可以使其适用于 java8。但如果持续时间不超过 24 小时,它会起作用

                public String formatDuration(Duration duration) {
                    DateTimeFormatter formatter = DateTimeFormatter.ofPattern("h:mm.SSS");
                    return LocalTime.ofNanoOfDay(duration.toNanos()).format(formatter);
                }
                

                【讨论】:

                • 这很好用,但这是什么魔法?大声笑为什么以及如何实际工作? ofNanoOfDaytoNanos...以及为什么LocalTime。在持续时间的背景下,这是没有意义的:-\ 但它确实成功了。
                • 第一票!你今天让我开心了:) Duration 需要转换成 LocalTime 才能使用它的 format 方法。至于 nanos,它们是用来获取毫秒数的,但我们也可以写类似LocalTime.ofSecondOfDay(duration.getSeconds()).format(formatter)
                • 酷!秒感觉更自然:-] 是的,要在这里获得一些代表需要很多工作,或者您必须非常幸运地为一个问题或答案获得数百张选票。人们非常不愿意投票。有时只是需要更多的时间让别人注意到你的答案。玩得开心,再次感谢这个简短的解决方案。其他的都过度设计了:)
                • 这是一个错误的答案,如果持续时间超过 24 小时,这将失败!
                【解决方案15】:
                String duration(Temporal from, Temporal to) {
                    final StringBuilder builder = new StringBuilder();
                    for (ChronoUnit unit : new ChronoUnit[]{YEARS, MONTHS, WEEKS, DAYS, HOURS, MINUTES, SECONDS}) {
                        long amount = unit.between(from, to);
                        if (amount == 0) {
                            continue;
                        }
                        builder.append(' ')
                                .append(amount)
                                .append(' ')
                                .append(unit.name().toLowerCase());
                        from = from.plus(amount, unit);
                    }
                    return builder.toString().trim();
                }
                

                【讨论】:

                  【解决方案16】:

                  使用这个函数

                  private static String strDuration(long duration) {
                      int ms, s, m, h, d;
                      double dec;
                      double time = duration * 1.0;
                  
                      time = (time / 1000.0);
                      dec = time % 1;
                      time = time - dec;
                      ms = (int)(dec * 1000);
                  
                      time = (time / 60.0);
                      dec = time % 1;
                      time = time - dec;
                      s = (int)(dec * 60);
                  
                      time = (time / 60.0);
                      dec = time % 1;
                      time = time - dec;
                      m = (int)(dec * 60);
                  
                      time = (time / 24.0);
                      dec = time % 1;
                      time = time - dec;
                      h = (int)(dec * 24);
                      
                      d = (int)time;
                      
                      return (String.format("%d d - %02d:%02d:%02d.%03d", d, h, m, s, ms));
                  }
                  

                  【讨论】:

                  • github.com/ipserc/duration获取这个函数的打包版本
                  • 这是我正在寻找的代码,接受的答案很好,但它缺少我需要的日子
                  【解决方案17】:

                  我的库Time4J 提供了基于模式的解决方案(类似于Apache DurationFormatUtils,但更灵活):

                  Duration<ClockUnit> duration =
                      Duration.of(-573421, ClockUnit.SECONDS) // input in seconds only
                      .with(Duration.STD_CLOCK_PERIOD); // performs normalization to h:mm:ss-structure
                  String fs = Duration.formatter(ClockUnit.class, "+##h:mm:ss").format(duration);
                  System.out.println(fs); // output => -159:17:01
                  

                  此代码演示了处理小时溢出和符号处理的功能,另请参见 duration-formatter 的 API based on pattern

                  【讨论】:

                    【解决方案18】:

                    这是在 Kotlin 中将 java.time.Duration 转换为漂亮字符串的单行代码:

                    duration.run {
                       "%d:%02d:%02d.%03d".format(toHours(), toMinutesPart(), toSecondsPart(), toMillisPart())
                    }
                    

                    示例输出: 120:56:03.004

                    【讨论】:

                      【解决方案19】:

                      在 scala 中(我看到了其他一些尝试,并没有留下深刻的印象):

                      def formatDuration(duration: Duration): String = {
                        import duration._ // get access to all the members ;)
                        f"$toDaysPart $toHoursPart%02d:$toMinutesPart%02d:$toSecondsPart%02d:$toMillisPart%03d"
                      }
                      

                      看起来很可怕是吗?这就是我们使用 IDE 编写这些东西的原因,以便方法调用($toHoursPart 等)具有不同的颜色。

                      f"..." 是一个 printf/String.format 样式的字符串插值器(这是允许$ 代码注入工作的原因) 给定1 14:06:32.583 的输出,f 内插字符串将等效于String.format("1 %02d:%02d:%02d.%03d", 14, 6, 32, 583)

                      【讨论】:

                      • OP 要求提供一种解决方案,以秒为单位格式化持续时间... Java
                      【解决方案20】:

                      查看所有这些计算,大多数单位(小时、分钟等)都具有.toFooPart() 便捷方法可能会有所帮助。

                      例如

                      Duration.ofMinutes(110L).toMinutesPart() == 50
                      

                      读取:到父单位的下一个值(小时)所经过的分钟数。

                      【讨论】:

                      • 不回答问题,请坚持。
                      【解决方案21】:

                      在 Scala 中,以 YourBestBet 的解决方案为基础,但经过简化:

                      def prettyDuration(seconds: Long): List[String] = seconds match {
                        case t if t < 60      => List(s"${t} seconds")
                        case t if t < 3600    => s"${t / 60} minutes" :: prettyDuration(t % 60)
                        case t if t < 3600*24 => s"${t / 3600} hours" :: prettyDuration(t % 3600)
                        case t                => s"${t / (3600*24)} days" :: prettyDuration(t % (3600*24))
                      }
                      
                      val dur = prettyDuration(12345).mkString(", ") // => 3 hours, 25 minutes, 45 seconds
                      

                      【讨论】:

                      • OP 要求提供一种解决方案,以秒为单位格式化持续时间... Java
                      【解决方案22】:

                      在 scala 中,不需要库:

                      def prettyDuration(str:List[String],seconds:Long):List[String]={
                        seconds match {
                          case t if t < 60 => str:::List(s"${t} seconds")
                          case t if (t >= 60 && t< 3600 ) => List(s"${t / 60} minutes"):::prettyDuration(str, t%60)
                          case t if (t >= 3600 && t< 3600*24 ) => List(s"${t / 3600} hours"):::prettyDuration(str, t%3600)
                          case t if (t>= 3600*24 ) => List(s"${t / (3600*24)} days"):::prettyDuration(str, t%(3600*24))
                        }
                      }
                      val dur = prettyDuration(List.empty[String], 12345).mkString("")
                      

                      【讨论】:

                      猜你喜欢
                      • 1970-01-01
                      • 2019-07-13
                      • 2014-01-16
                      • 2023-03-07
                      • 1970-01-01
                      • 2015-09-10
                      • 1970-01-01
                      • 1970-01-01
                      • 2014-10-31
                      相关资源
                      最近更新 更多