Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is the easiest way to deserialize human readable time duration in Java?

I need to have configurable timeout for a project, which reads different configs from YAML file.

I noticed that java.time.Duration has method parse which is used by Jackson to deserialize duration strings. The problem is that it uses ISO-8601 formatting and expects the duration to have PnDTnHnMn.nS format. While it is a good idea to follow standards, asking people provide timeout as PT10M is not the best option and 10m is preferred.

I did write a custom deserializer for duration fields, but seems strange that Jackson can't handle this by default.

What is the easiest way to deserialize human friendly 10m, 5s and 1h to java.time.Duration using Jackson ObjectMapper?

like image 422
DaTval Avatar asked Nov 15 '25 07:11

DaTval


1 Answers

"Easiest" way to deserialize human friendly 10m, 5s and 1h is likely a combination of regex and Java code.

public static Duration parseHuman(String text) {
    Matcher m = Pattern.compile("\\s*(?:(\\d+)\\s*(?:hours?|hrs?|h))?" +
                                "\\s*(?:(\\d+)\\s*(?:minutes?|mins?|m))?" +
                                "\\s*(?:(\\d+)\\s*(?:seconds?|secs?|s))?" +
                                "\\s*", Pattern.CASE_INSENSITIVE)
                       .matcher(text);
    if (! m.matches())
        throw new IllegalArgumentException("Not valid duration: " + text);
    int hours = (m.start(1) == -1 ? 0 : Integer.parseInt(m.group(1)));
    int mins  = (m.start(2) == -1 ? 0 : Integer.parseInt(m.group(2)));
    int secs  = (m.start(3) == -1 ? 0 : Integer.parseInt(m.group(3)));
    return Duration.ofSeconds((hours * 60L + mins) * 60L + secs);
}

Test

System.out.println(parseHuman("1h"));
System.out.println(parseHuman("1 hour 200 minutes"));
System.out.println(parseHuman("3600 secs"));
System.out.println(parseHuman("2h3m4s"));

Output

PT1H
PT4H20M
PT1H
PT2H3M4S
like image 155
Andreas Avatar answered Nov 17 '25 20:11

Andreas