Java - 在 Netbeans 中将毫秒转换为“HH:mm:ss:SSS”时的结果不正确 IDE

Java - Incorrect result when convert Millisecond to `HH:mm:ss:SSS` in Netbeans IDE

我正在尝试将 5007 转换为 HH:mm:ss:SSS,我正在使用 Netbeans IDE v8.2:

Date date = new Date(5007);
DateFormat formatter = new SimpleDateFormat("HH:mm:ss:SSS");
String dateFormatted = formatter.format(date);

但这给了我一个错误的结果:

01:00:05:007
^^-------------------------why does it print to me 01 in the hours?

但它应该得到:

00:00:05:007
^^-------------------------correct result

例如,当我使用 ideone 时,它给出了正确的结果:

有没有关于这个问题的解释?

我测试了两个版本:Java 7 和 Java 8。

Date date = new Date(5007);

创建一个在 January 1, 1970, 00:00:00 GMT 后 5007 毫秒的日期。

当您使用 SimpleDateFormat 格式化时,它会转换为您机器的时区(我假设是 GMT+1)。

当我运行你的代码时我得到

02:00:05:007

我的时区是 GMT+2。

如果将 DateFormat 实例的时区设置为 GMT,您将获得预期的输出:

Date date = new Date(5007);
DateFormat formatter = new SimpleDateFormat("HH:mm:ss:SSS");
formatter.setTimeZone (TimeZone.getTimeZone ("GMT"));
String dateFormatted = formatter.format(date);
System.out.println (dateFormatted);

这会打印

00:00:05:007

肯定是语言环境问题。当您不指定时,它将使用(您的系统)默认值。要覆盖它;

尝试添加这个

formatter.setTimeZone(TimeZone.getTimeZone("UTC"));

或者在构造 SimpleDateFormat 实例时传递 Locale。例如:

DateFormat formatter = new SimpleDateFormat("HH:mm:ss:SSS", Locale.ENGLISH); 

我假设 Locale.ENGLISH 有 UTC 时区顺便说一下,但我希望你明白了。

当你要求解释你的问题时,我会诚实地告诉你:你误用了 SimpleDateFormat 来格式化持续时间。它从来就不是为了这种用途而设计的,而且如果您尝试它,也不会为您提供预期的结果。您遇到的问题并不是您将遇到的唯一问题。如果你的持续时间增长到超过 24 小时,整天都不会被格式化,所以你的结果会以不同的方式出错。

除此之外,最近我建议完全不要使用 SimpleDateFormat class。它的替代品是 java.time.format.DateTimeFormatter,它于 2014 年问世,带来的负面惊喜要少得多。不过,这也不是格式化持续时间的好选择。

那么什么是好的选择呢?我会先给你 Java 9 个答案,因为它很简单:

        Duration dur = Duration.ofMillis(5007);
        String hmss = String.format("%02d:%02d:%02d:%03d", 
                                    dur.toHours(),
                                    dur.toMinutesPart(), 
                                    dur.toSecondsPart(), 
                                    dur.toMillisPart​());

主要优点甚至不是简单,而是清晰。例如,使用此代码,没有人需要问我在评论中提出的问题,它是时间点还是持续时间?代码写的很清楚,就是一个时长。

对于 Java 6、7 和 8,您仍然可以使用 Duration class(在 Java 6 和 7 中通过 ThreeTen Backport), but it doesn’t lend itself that easily to formatting, so I think I would resort to using the TimeUnit enum as in the question I had linked to( link 你让我再次删除):

    long millis = 5007;
    long hours = TimeUnit.MILLISECONDS.toHours(millis);
    millis -= TimeUnit.HOURS.toMillis(hours);
    long minutes = TimeUnit.MILLISECONDS.toMinutes(millis);
    millis -= TimeUnit.MINUTES.toMillis(minutes);
    long seconds = TimeUnit.MILLISECONDS.toSeconds(millis);
    millis -= TimeUnit.SECONDS.toMillis(seconds);
    String hmss = String.format("%02d:%02d:%02d:%03d", hours, minutes, seconds, millis);

结果如愿

00:00:05:007

为了说明我试图说明的关于持续时间超过 24 小时时会发生什么的观点,让我们尝试给它 100 000 000 毫秒(一天有 86 400 000 毫秒):

27:46:40:000