在 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 你是如何导入 TemporalUnitHOURS
?
@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 小虚竹,建议收藏)