Java中如何将混合日期时间单位的时长字符串解析为Period/Duration实例
实现方案
Java 8+ 自带的Period和Duration本身是职责拆分的:前者仅支持年、月、日等日期单位,后者仅支持时、分、秒等时间单位,所以混合单位的字符串无法直接解析为单个Period或Duration实例,你可以选择分开存储为两个实例,或者使用组合类存储。
方案1:纯JDK原生实现(无需引入第三方依赖)
核心思路是通过正则匹配字符串中所有「数值+单位」的片段,按单位类型分别归集到Period和Duration对象中,同时兼容单位的单复数、大小写格式。
解析代码示例
import java.time.Duration; import java.time.Period; import java.util.regex.Matcher; import java.util.regex.Pattern; public class TimeAmountParser { // 预编译匹配正则,适配单位单复数与大小写 private static final Pattern TIME_PATTERN = Pattern.compile("(\\d+)\\s+(years?|months?|days?|hours?|minutes?|seconds?)", Pattern.CASE_INSENSITIVE); // 解析结果封装类,可按需调整结构 public static class ParsedTimeAmount { private final Period period; private final Duration duration; public ParsedTimeAmount(Period period, Duration duration) { this.period = period; this.duration = duration; } public Period getPeriod() { return period; } public Duration getDuration() { return duration; } } public static ParsedTimeAmount parse(String input) { Matcher matcher = TIME_PATTERN.matcher(input); int years = 0, months = 0, days = 0; long hours = 0, minutes = 0, seconds = 0; while (matcher.find()) { long value = Long.parseLong(matcher.group(1)); String unit = matcher.group(2).toLowerCase(); switch (unit) { case "year": case "years": years = (int) value; break; case "month": case "months": months = (int) value; break; case "day": case "days": days = (int) value; break; case "hour": case "hours": hours = value; break; case "minute": case "minutes": minutes = value; break; case "second": case "seconds": seconds = value; break; default: throw new IllegalArgumentException("不支持的时间单位: " + unit); } } return new ParsedTimeAmount( Period.of(years, months, days), Duration.ofHours(hours).plusMinutes(minutes).plusSeconds(seconds) ); } // 测试用例 public static void main(String[] args) { // 测试示例1 String test1 = "29 days 23 hours 59 minutes 20 seconds"; ParsedTimeAmount result1 = parse(test1); System.out.println(result1.getPeriod()); // 输出P29D System.out.println(result1.getDuration()); // 输出PT23H59M20S // 测试示例2 String test2 = "4 years 10 months 10 seconds"; ParsedTimeAmount result2 = parse(test2); System.out.println(result2.getPeriod()); // 输出P4Y10M System.out.println(result2.getDuration()); // 输出PT10S } }
方案2:用单个对象存储混合时间量
如果你希望用单个对象承载所有时间量,可以使用ThreeTen Extra库中的PeriodDuration类,该类是JSR310时间体系的官方扩展类,专门适配同时包含日期和时间单位的时间量场景,解析完成后直接调用PeriodDuration.of(period, duration)即可构造对应实例。
扩展说明
- 如果需要支持毫秒、周等其他单位,只需要在正则规则和switch分支中补充对应配置即可
- 如果需要自动做单位转换(比如25小时自动转为1天1小时),可以在解析完成后调用
Duration#toDaysPart等内置方法转换后更新Period数值即可
内容的提问来源于stack exchange,提问作者Marwi
相关产品推荐
相关产品推荐

