如何在Java中以hh:mm:ss.SSS格式格式化经过的时间间隔?

如何在Java中以hh:mm:ss.SSS格式格式化经过的时间间隔?,java,time,simpledateformat,Java,Time,Simpledateformat,我正在制作秒表,使用Java的SimpleDataFormat将毫秒数转换为一个漂亮的“hh:mm:ss:SSS”格式。问题是小时字段中总是有一些随机数。以下是我使用的代码: public static String formatTime(long millis) { SimpleDateFormat sdf = new SimpleDateFormat("hh:mm:ss.SSS"); String strDate = sdf.format(millis); retu

我正在制作秒表,使用Java的SimpleDataFormat将毫秒数转换为一个漂亮的“hh:mm:ss:SSS”格式。问题是小时字段中总是有一些随机数。以下是我使用的代码:

public static String formatTime(long millis) {
    SimpleDateFormat sdf = new SimpleDateFormat("hh:mm:ss.SSS");

    String strDate = sdf.format(millis);
    return strDate;
}
如果我去掉hh部分,它就可以正常工作了。否则,在hh部分中,即使传入的参数(毫秒数)为零,它也会显示一些随机值,如“07”


但是我对SimpleDateFormat类知之甚少。谢谢您的帮助。

格式根据您的本地时区而定,因此如果您超过0,它将假定为0 GMT,然后在您的本地时区中转换它。

下面是发生的情况。当你通过毫秒,这个数字是相对于1970年1月1日。当您传递0时,它将获取该日期并将其转换为您的本地时区。如果你在中心时间,那正好是晚上7点。如果你运行这个,那么一切都是有意义的

new SimpleDateFormat().format(0) => 12/31/69 7:00 PM
编辑,我想你要做的是得到经过的时间。为此,我建议使用已经做得很好的。你做的事情

PeriodFormatter formatter = new PeriodFormatterBuilder()
    .appendHours()
    .appendSuffix(" hour", " hours")
    .appendSeparator(" and ")
    .appendMinutes()
    .appendSuffix(" minute", " minutes")
    .appendSeparator(" and ")
    .appendSeconds()
    .appendSuffix(" second", " seconds")
    .toFormatter();

String formattedText = formatter.print(new Period(elapsedMilliSeconds));
最新的JDK内置了对所需操作的支持,其中包含一个鲜为人知的类,名为
TimeUnit
。 您要使用的是使用间隔

SimpleDataFormat
只做它听起来像做的事情,它格式化
java.util.Date
的实例,或者在您的例子中,它将
long
值转换为
java.util.Date
的上下文,它不知道如何处理间隔,这显然是您正在使用的

您可以很容易地做到这一点,而不必求助于像JodaTime这样的外部库

import java.util.concurrent.TimeUnit;

public class Main
{        
    private static String formatInterval(final long l)
    {
        final long hr = TimeUnit.MILLISECONDS.toHours(l);
        final long min = TimeUnit.MILLISECONDS.toMinutes(l - TimeUnit.HOURS.toMillis(hr));
        final long sec = TimeUnit.MILLISECONDS.toSeconds(l - TimeUnit.HOURS.toMillis(hr) - TimeUnit.MINUTES.toMillis(min));
        final long ms = TimeUnit.MILLISECONDS.toMillis(l - TimeUnit.HOURS.toMillis(hr) - TimeUnit.MINUTES.toMillis(min) - TimeUnit.SECONDS.toMillis(sec));
        return String.format("%02d:%02d:%02d.%03d", hr, min, sec, ms);
    }

    public static void main(final String[] args)
    {
        System.out.println(formatInterval(Long.parseLong(args[0])));
    }
}
输出的格式如下

13:00:00.000

这是我所做的Joda工作的第一部分,它似乎比JDK支持更乏味。请求格式的Joda实现(对零字段进行一些假设)是:


下面是我如何做到这一点的,仅使用标准JDK(这将通过将
StringBuilder
更改为
StringBuffer
,在Java 1.1中就可以实现):

静态公共字符串格式millis(long val){
StringBuilder buf=新StringBuilder(20);
字符串sgn=“”;
if(val1){
int pad=(dgt-1);
对于(长xa=val;xa>9&&pad>0;xa/=10){pad--;}

对于(int xa=0;xa使用普通Java
日历
的时间间隔长达一天(24小时),请参见我对问题的回答:

一种较短的方法是在以下情况下使用该类:

为什么不是这个

public static String GetFormattedInterval(final long ms) {
    long millis = ms % 1000;
    long x = ms / 1000;
    long seconds = x % 60;
    x /= 60;
    long minutes = x % 60;
    x /= 60;
    long hours = x % 24;

    return String.format("%02d:%02d:%02d.%03d", hours, minutes, seconds, millis);
}
变体:最多24小时 对于小于24小时的运行时间,简单的格式化。超过24小时,代码将只显示第二天的小时数,而不会将运行的日期添加到小时数中

public static String formatElapsedTime(long milliseconds) {

    SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss.SSS");
    sdf.setTimeZone(TimeZone.getTimeZone("UTC"));

    return sdf.format(milliseconds);
}
示例代码中缺少功能:

  • 用“UTC”消除时区
  • 使用24小时格式“HH”
变体:超过24小时
这是另一种方法。完全独立且完全向后兼容。天数不限

private static String slf(double n) {
  return String.valueOf(Double.valueOf(Math.floor(n)).longValue());
}

public static String timeSpan(long timeInMs) {
  double t = Double.valueOf(timeInMs);
  if(t < 1000d)
    return slf(t) + "ms";
  if(t < 60000d)
    return slf(t / 1000d) + "s " +
      slf(t % 1000d) + "ms";
  if(t < 3600000d)
    return slf(t / 60000d) + "m " +
      slf((t % 60000d) / 1000d) + "s " +
      slf(t % 1000d) + "ms";
  if(t < 86400000d)
    return slf(t / 3600000d) + "h " +
      slf((t % 3600000d) / 60000d) + "m " +
      slf((t % 60000d) / 1000d) + "s " +
      slf(t % 1000d) + "ms";
  return slf(t / 86400000d) + "d " +
    slf((t % 86400000d) / 3600000d) + "h " +
    slf((t % 3600000d) / 60000d) + "m " +
    slf((t % 60000d) / 1000d) + "s " +
    slf(t % 1000d) + "ms";
}
私有静态字符串slf(双n){
返回字符串.valueOf(Double.valueOf(Math.floor(n)).longValue());
}
公共静态字符串时间跨度(长时间inms){
double t=double.valueOf(timeInMs);
如果(t<1000d)
返回slf(t)+“ms”;
如果(t<60000d)
返回slf(t/1000d)+“s”+
slf(t%1000d)+“ms”;
如果(t<3600000d)
返回slf(t/60000d)+“m”+
slf(t%60000d)/1000d)+“s”+
slf(t%1000d)+“ms”;
如果(t<86400000d)
返回slf(t/3600000d)+“h”+
slf(t%3600000d)/60000d)+“m”+
slf(t%60000d)/1000d)+“s”+
slf(t%1000d)+“ms”;
返回slf(t/86400000d)+“d”+
slf(t%86400000d)/3600000d)+“h”+
slf(t%3600000d)/60000d)+“m”+
slf(t%60000d)/1000d)+“s”+
slf(t%1000d)+“ms”;
}

回顾其他答案,我想出了这个函数

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

这个方法实际上是有效的,但似乎我正在调整方法的意图:-)

对于那些真正了解这一原理的人,您可能会发现一些注意事项
java.time.Duration
表示未附加到时间线的时间跨度(以小时-分钟-秒为刻度)的适当类为。对于年-月-天的刻度,请使用

ISO 8601格式 我建议您避免使用HH:MM:SS的时间格式报告时间跨度。我已经看到,在现实世界的商业应用程序中,固有的模糊性会导致误解和混乱

报告此类值有一个标准,具体如下:
PnYnMnDTnHnMnS
p
标记开始,而
T
将任何年-月-日部分与任何时-分-秒部分分开

java.time类在解析/生成字符串时默认使用ISO 8601标准格式。这包括
Duration

Duration d = Duration.ofMillis( 5_025_678L ) ;
String output = d.toString() ;
看这个

PT1H23M45.678S

这些ISO 8601字符串可以被解析和生成

Duration d = Duration.parse( "PT1H23M45.678S" ) ;
时间格式 但是如果您坚持在持续时间中使用每日时间格式,您可以通过调用
duration
对象上的
to…Part
方法来组合这样一个sting

Duration d = Duration.ofMillis( 5_025_678L ) ;
String output = d.toHoursPart() + ":" + d.toMinutesPart() + ":" + d.toSecondsPart() + "." + TimeUnit.NANOSECONDS.toMillis( d.toNanosPart() ) ;
1:23:45.678

或者我们可以滥用
LocalTime
类来创建字符串

Duration d = Duration.ofMillis( 5_025_678L ) ;
long nanoOfDay = d.toNanos() ;
LocalTime localTimeBogus = LocalTime.ofNanoOfDay( nanoOfDay ) ;
String output = localTimeBogus.toString() ;
同样,你可以看到这一点

01:23:45.678


可以在DATUUTILS类中使用或方法.< /P>从中我们可以推断出你位于美国中部某个地方。使用24H格式<代码> HH>代码>代替<代码> HH。消除时区<代码> SDF.StimeTimeStand(TimeZeal.GETTimeZONE(UTC));

。请参阅下面的答案。类似问题是的,这就是实际情况。夏令时,所以CDT,而不是EDT我同意,SimpleDataFormat的设计目的不是格式化经过的时间。更容易编写自己的格式化程序或使用Joda格式化程序
public static String formatTime(long millis) {
    SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss.SSS");

    String strDate = sdf.format(millis - 3600000);
    return strDate;
}
LocalTime                     // Represents a time-of-day, without date and without time zone.
.ofNanoOfDay(                 // Convert a count of nanoseconds into a time-of-day in a generic 24-hour day, ignoring real-world anomalies such as Daylight Saving Time (DST). 
    Duration                  // Class that represents a span-of-time not attached to the timeline.
    .of( milliseconds )       // Parse your count of milliseconds as a span-of-time.
    .toNanos()                // Extract total number of nanoseconds in this span-of-time.
)                             // Returns a `LocalDate` object.
.toString()                   // Generate text in standard ISO 8601 format for a time-of-day (*not* recommended by me). 
Duration d = Duration.of( milliseconds ) ;
Duration d = Duration.ofMillis( 5_025_678L ) ;
String output = d.toString() ;
Duration d = Duration.parse( "PT1H23M45.678S" ) ;
Duration d = Duration.ofMillis( 5_025_678L ) ;
String output = d.toHoursPart() + ":" + d.toMinutesPart() + ":" + d.toSecondsPart() + "." + TimeUnit.NANOSECONDS.toMillis( d.toNanosPart() ) ;
Duration d = Duration.ofMillis( 5_025_678L ) ;
long nanoOfDay = d.toNanos() ;
LocalTime localTimeBogus = LocalTime.ofNanoOfDay( nanoOfDay ) ;
String output = localTimeBogus.toString() ;
org.apache.commons.lang.time.DurationFormatUtils.formatDuration(stopWatch.getTime(), "HH:mm:ss")