在 Java 8 / jsr310 中格式化持续时间

Posted

技术标签:

【中文标题】在 Java 8 / jsr310 中格式化持续时间【英文标题】:Formatting a Duration in Java 8 / jsr310 【发布时间】:2014-01-16 14:25:48 【问题描述】:

我正在将一个项目从 Joda-Time 转换到 java8 的本地时间库,但我遇到了障碍。

我一直找不到 Duration 的格式化程序。我想要一个自定义字符串格式,例如 HHH+MM,其中 75 小时 15 分钟的持续时间将格式化为 "75+15"

这很容易通过 Joda-Time 转换为句点并使用 PeriodFormatter 来完成,但我在 Java8 中找不到这种类型的类。我错过了什么吗?

【问题讨论】:

How to format a duration in java? (e.g format H:MM:SS)的可能重复 @MartinSchröder 这个问题是关于格式化持续时间(以任何形式),鉴于它早于 Java 8,它并不是专门关于格式化 java.time.Duration。在这个问题中,OP 询问他是否错过了 java.time 中存在的格式化程序 java.time.Duration。所以问题是相关的,但不是重复的。 对我来说,duration.get().toMillis() 有效。我只是在尝试duration.toMillis 【参考方案1】:

jsr-310 中没有句点/持续时间格式化程序,与 JodaTime 不同。并非 JodaTime 的每个功能都被移植到 JSR-310(例如,也不是 PeriodType)。反过来,JSR-310 有一些 JodaTime 不具备的功能(例如本地化的工作日数字或带有调整器的策略模式方法)。

Java 9 可能会引入某种内置的句点格式(从 S. Colebourne 阅读有关此的内容)。

结论:JSR-310 和 JodaTime 之间并不完全兼容,因此可能需要做很多工作。我不会那么热衷于尽快迁移。您是否需要 JodaTime 不提供的 JSR-310 特殊功能?

附加说明:您还应该知道,joda period(包括从年到秒的所有单位)与 jsr310-period(仅年、月、日)或 jsr310-duration(仅小时)不完全兼容这一事实、分、秒和小数秒)。

【讨论】:

谢谢,我想我只能自己动手了。这对我来说是一个爱好项目,所以它更像是旅程而不是目的地。:) 即使它缺少一些功能,我认为 JSR-310 最终会在 jaxb 等其他库中获得更好的开箱即用支持. 就我个人而言,我看到 jsr 310 与其他库的集成并不是那么好。例如,JAXB 集成不会在 Java 8 中发生。但是有一些可用的解决方法,比如 JodaTime,所以 JAXB 不是一个困难的障碍。 @MenoHochschild 您还可以获得由 Duration 表示的天数(除了小时、分钟、秒和纳秒之外)。 @assylias 没错。我忽略了这个小细节。但事实是 JSR-310 中的 Duration 并不接受所有单位。更糟糕的是,由于内部转换为仅秒和纳秒,许多在持续时间构造中允许的单位在查询中并不真正支持(或仅以混乱的方式 - 请参阅您的示例)。基本问题是您在 Duration 中放入的内容不是您输出的内容。【参考方案2】:

没有内置方法,但您可以访问小时/分钟数,而无需手动计算它们。您的具体格式可能如下所示:

Duration d = Duration.of(75, HOURS).plusMinutes(15);
long hours = d.toHours(); //75
long minutes = d.minusHours(hours).toMinutes(); //15
String HH_PLUS_MM = hours + "+" + minutes; //75+15
System.out.println(HH_PLUS_MM);

如果保证时长小于24小时,也可以使用这个技巧:

String hhPlusMm = LocalTime.MIDNIGHT.plus(d).format(DateTimeFormatter.ofPattern("HH+mm"));

【讨论】:

查询时长有多乱,但这不是你的错。在构建时长时可以使用小时和分钟,但不可能在标准方法 get(TemporalUnit) 中直接使用这些单位 :-( 我知道我为什么要开发自己的时间库。 @MenoHochschild 该 api 非常适合使用 Duration 作为 DateTimes 的偏移量,但实际上并不适合作为独立对象。如果你有想法,你可以为 310 做出贡献(尽管现在对 Java 8 来说已经太晚了)! @assylias 你是如何导入 TemporalUnit HOURS @IgorGanapolsky import static java.time.temporal.ChronoUnit.HOURS;【参考方案3】:

我知道这是一个老问题,但我最近遇到了同样的事情。确实应该有比这更好的解决方案,但这对我有用:

public static String millisToElapsedTime(long millis)
    DateFormat fmt = new SimpleDateFormat(":mm:ss.SSS");
    fmt.setTimeZone(TimeZone.getTimeZone("UTC"));
    return (millis/3600000/*hours*/)+fmt.format(new Date(millis));

然后,您可以添加以下内容:

public static String durationToElapsedTime(Duration d)
    return millisToElapsedTime(d.toMillis());

【讨论】:

在这里记录 12:00:00.022 持续 22 毫秒 对此感到抱歉 - SDF 字符串中存在错误 - 请改用大写“HH”。 经过进一步思考,我意识到这仍然只能持续长达 24 小时。我已将其修复为允许超过 24 小时。【参考方案4】:

Java 9 及更高版本:Duration::to…Part 方法

在 Java 9 中,Duration 类 gained new to…Part methods 用于返回天、小时、分钟、秒、毫秒/纳秒的各个部分。看到这个pre-release OpenJDK source code。

鉴于持续时间为 49H30M20.123S…

toNanosPart() = 123000000 toMillisPart() = 123 toSecondsPart() = 20 toMinutesPart() = 30 toHoursPart() = 1 toDaysPart() = 2

请记住,这里的“天”表示 24 小时的时间段,忽略日历上的日期。如果您关心日期,请改用Period 类。

我不知道是否添加了任何其他格式化程序功能。但至少您将能够更方便地从通过这些新的 getter 方法获得的数字生成自己的字符串。

Java 8

奇怪的是,Java 8 的 java.time 的第一版中没有包含这些值的方便的 getter 方法。在 java.time 的其他出色设计中,这是极少数的疏忽之一框架。

查看相关问题:Why can't I get a duration in minutes or hours in java.time?。

【讨论】:

【参考方案5】:

您可以使用 commons-lang3-time 中的 DurationFormatUtils(对于分钟,您必须使用“mm”,因为格式与 SimpleDateFormat 中的格式相同): DurationFormatUtils.formatDuration(interval.toMillis(), "HHH+mm")

遗憾的是,我发现无法排除空白部分,比如在我的情况下,天数或小时数可能为 0,所以我仍然不得不自己动手。

更新:我已经打开an issue for this on Apache commons.lang.time.DurationFormatUtils JIRA。

【讨论】:

DurationFormatUtils.formatDurationWords 可用于排除空字段。 DurationFormatUtils.formatDurationWords(interval.toMillis(), true, true) 在 java 8 上使用的最佳解决方案,非常感谢!!!

以上是关于在 Java 8 / jsr310 中格式化持续时间的主要内容,如果未能解决你的问题,请参考以下文章

java 使用Java 8 Date and Time API(JSR 310)的示例

高级JAVA开发必备技能:java8 新日期时间API(JSR-310:格式化和解析)(JAVA 小虚竹)

即使使用 jackson-datatype-jsr310,Instant 也无法序列化为适当的格式

如何正确地在Spring Data JPA和Jackson中用上Java 8的时间相关API(即JSR 310也即java.time包下的众神器)

springboot Thymeleaf中格式化jsr310新日期时间类(LocalDateTime,LocalDate)

❤️高级JAVA开发必备技能❤️java8 新日期时间API(JSR-310:格式化和解析),2万字详解(JAVA 小虚竹,建议收藏)