SimpleDateFormat returns 错误的天数

SimpleDateFormat returns wrong number of days

我需要从长值中获取天数、小时数、分钟数、秒数。但是我从以下代码中得到错误的天数。

public static String formatTimeUTC(long value, String pattern) {
    final SimpleDateFormat format = new SimpleDateFormat(pattern, Locale.US);
    format.setTimeZone(TimeZone.getTimeZone("UTC"));
    Date date = new Date(value);
    String formatString = format.format(date);
    return formatString;
}

当我将 106988550"dd:HH:mm:ss" 传递给此方法时,我得到 "02:05:43:08"

预期的实际答案是:"01:05:43:08"

我不知道哪里错了,我怎么才能得到真正的答案。

改变你的TimeZone这个

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

至此

format.setTimeZone(TimeZone.getTimeZone("GMT+0:00"));

并检查输出。

表达式 System.out.println(formatTimeUTC(106988550L, "dd:HH:mm:ss")); 确实需要多打印一天 (02:05:43:08)。为什么?

摘要:

class SimpleDateFormat 并非设计用于打印持续时间,而是打印时间点。对于旧类型 java.util.Date 也可以这样说,它不是持续时间而是瞬间。

具体:

模式部分 "dd" 指示格式化程序打印名义上的日期,而不是自 UNIX 纪元以来的天数。 在这种情况下,它是日历日期 1970-01-02T05:43:08.550 的一部分。所以你需要从UNIX纪元的原始日期1减去一天。

备选方案:

如您所见,以这种方式打印持续时间变得非常尴尬(通过滥用并非为此目的设计的 class SimpleDateFormat)。我建议使用更好的 APIs。例如 Joda-Time or my library Time4J:

Joda-Time(基于builder-approach):

PeriodFormatter pf =
    new PeriodFormatterBuilder().minimumPrintedDigits(2).appendDays().appendLiteral(":")
    .appendHours().appendLiteral(":").appendMinutes().appendLiteral(":").appendSeconds()
    .toFormatter();
long v = 106988550L;
System.out.println(
    pf.print(new Period(v, PeriodType.dayTime()).normalizedStandard())); // 01:05:43:08

对于Android:使用改编Joda-Time-Android


Time4J(基于pattern approach):

long v = 106988550L;
Duration<IsoUnit> duration = Duration.of(v, ClockUnit.MILLIS);
System.out.println(
    Duration.formatter("DD:hh:mm:ss").format(duration.with(Duration.STD_PERIOD))
); // 01:05:43:08

对于Android:使用姊妹项目Time4A。


您也可以调查 Android 平台 中内置的 class DateUtils,尽管我不确定它是否适合您的目的因为它的 API 很笨拙(无论如何你都需要设置位标志的组合)。

是正确的。您正在处理一个时间跨度作为日期时间,喜欢将苹果和橙子混合在一起。

java.time

java.time 类 取代了麻烦的旧日期时间 类。让这项工作变得简单。

你实际上没有解释,但我猜你的数字是经过的毫秒数。

long input = 106_988_550L ;

我们将其表示为 Duration

Duration d = Duration.ofMillis( input );

我们可以将该值表示为使用标准 ISO 8601 format for durations, PTnHnMnS.

的子集格式化的字符串
String output = d.toString();

PT29H43M8.55S

参见 live code in IdeOne.com

在 Java 9 及更高版本中,您可以通过调用 to…Part 方法(例如 toDaysParttoHoursPart 等)来访问该值的每个组件


关于java.time

java.time framework is built into Java 8 and later. These classes supplant the troublesome old legacy date-time classes such as java.util.Date, Calendar, & SimpleDateFormat.

Joda-Time project, now in maintenance mode, advises migration to the java.time 类.

要了解更多信息,请参阅 Oracle Tutorial. And search Stack Overflow for many examples and explanations. Specification is JSR 310

在哪里获取java.time类?

  • Java SE 8 and SE 9 及更高版本
    • 内置。
    • 标准 Java API 的一部分,带有捆绑实施。
    • Java 9 添加了一些小功能和修复。
  • Java SE 6 and SE 7
  • Android
    • ThreeTenABP项目专门为Android改编了ThreeTen-Backport(上面提到的)。
    • 参见

ThreeTen-Extra project extends java.time with additional classes. This project is a proving ground for possible future additions to java.time. You may find some useful classes here such as Interval, YearWeek, YearQuarter, and more.

您可以使用 java.time.Duration which is modelled on ISO-8601 standards and was introduced with Java-8 as part of JSR-310 implementationJava-9 引入了一些更方便的方法。

演示:

import java.time.Duration;

public class Main {
    public static void main(String[] args) {
        long value = 106988550;

        Duration duration = Duration.ofMillis(value);
        // Default format
        System.out.println(duration);

        // Custom format
        // ####################################Java-8####################################
        String formattedElapsedTime = String.format("%02d:%02d:%02d:%02d", duration.toDays(), duration.toHours() % 24,
                duration.toMinutes() % 60, duration.toSeconds() % 60);
        System.out.println(formattedElapsedTime);
        // ##############################################################################

        // ####################################Java-9####################################
        formattedElapsedTime = String.format("%02d:%02d:%02d:%02d", duration.toDaysPart(), duration.toHoursPart(),
                duration.toMinutesPart(), duration.toSecondsPart());
        System.out.println(formattedElapsedTime);
        // ##############################################################################
    }
}

输出:

PT29H43M8.55S
01:05:43:08
01:05:43:08

Trail: Date Time.

了解现代日期时间 API
  • 出于任何原因,如果您必须坚持使用 Java 6 或 Java 7,您可以使用 ThreeTen-Backport,它向后移植了大部分 java.time Java 6 和 7 的功能。
  • 如果您正在为 Android 项目工作,并且您的 Android API 水平仍然不符合 Java-8,请检查 Java 8+ APIs available through desugaring and