4

I want to parse a string like 1d2h3m4s into a java.time.Duration. I can use a joda's PeriodFormatter to parse the string into a org.joda.time.Duration but I can't figure out how to convert that to a standard Java8's java.time.Duration.

I have to interface to some "legacy" code that already expects java.time.Duration as input, but I want to use joda's parsePeriod because the java.time.Duration.parse() only accepts ISO-8601 duration format (1d2h3m4s is not ISO-8601 duration compliant)

import org.joda.time.format.PeriodFormatter;
import org.joda.time.format.PeriodFormatterBuilder;

...

final PeriodFormatter periodFormatter = new PeriodFormatterBuilder()
        .printZeroNever()
        .appendDays().appendSuffix("d")
        .appendHours().appendSuffix("h")
        .appendMinutes().appendSuffix("m")
        .appendSeconds().appendSuffix("s").toFormatter();

org.joda.time.Duration myduration = periodFormatter.parsePeriod("1d1s").toStandardDuration(); 
java.util.time myduration2 = XXXXX

Please bear in mind that I'm not trying to remove the usage of org.joda.time.Period from my code like in Converting org.joda.time.Period to java.time.Period. I still want to have a org.joda.time.Period because I have more parsing option to generate those, and I need a java.time.Period/java.time.Duration because I interact with some other API/libraries that expect java.time.*.

So, is there a way to convert a org.joda.time.Duration to a java.time.Duration?

RubenLaguna
  • 21,435
  • 13
  • 113
  • 151
  • Does this answer your question? [Converting org.joda.time.Period to java.time.Period](https://stackoverflow.com/questions/47217098/converting-org-joda-time-period-to-java-time-period) – www.hybriscx.com Oct 31 '19 at 07:52
  • Not really, in that question the OP is not trying to convert one instance of `org.joda.time.Period` to an instance of `java.time.Period` at all. He is asking how to *replace* a joda's `Period` with a `java.time.Period` , so he won't have any joda's instance at all. I want to have both a joda's `Period` (because I have more options to parse there) and a `java.time.Period` (well `java.time.Duration` ) because I have other code that expects the input in this type. – RubenLaguna Oct 31 '19 at 08:20

2 Answers2

4

I am presenting three options

  1. Hand modify the string to ISO 8601 format so that java.time.Duration can parse it.
  2. Convert through count of milliseconds.
  3. Convert from joda.time.Duration.toString().

Modify the string

Personally I don’t think I would want to depend in Joda-Time for this. Instead I would modify your non-ISO 8601 string to ISO 8601 format.

    String durationString = "1d1s";
    // Convert to ISO 8601 format
    String isoString = durationString.replaceFirst("(.*?[Dd])?(.*)", "P$1T$2");
    java.time.Duration dur = java.time.Duration.parse(isoString);
    System.out.println(dur);

Output is:

PT24H1S

I admit that the regular expression is a bit hard to read. If there is an uppercase or lowercase D in the string, everything up to and including that D is placed before the T in the ISO string. Everything else is placed after the T.

Convert over milliseconds

This is an idea similar to the one in the answer by ecerulm. I didn’t want to lose the millisecond precision of the Joda-Time duration, so I rely of milliseconds rather than seconds (I know that for your example strings it will make no difference).

    final PeriodFormatter periodFormatter = new PeriodFormatterBuilder()
            .printZeroNever()
            .appendDays().appendSuffix("d")
            .appendHours().appendSuffix("h")
            .appendMinutes().appendSuffix("m")
            .appendSeconds().appendSuffix("s").toFormatter();

    org.joda.time.Duration myduration = periodFormatter.parsePeriod("1d1s").toStandardDuration(); 

    java.time.Duration dur = java.time.Duration.ofMillis(myduration.getMillis());

The result is the same as before.

Convert over a string

    java.time.Duration dur = java.time.Duration.parse(myduration.toString());

Again the result is the same. Formatting the duration into an ISO 8601 string only to parse it back feels like a waste, though.

Ole V.V.
  • 81,772
  • 15
  • 137
  • 161
0

You can just convert the org.joda.time.Period returned by PeriodFormatter#parse() to seconds using Period#toStandardSeconds()#getSeconds(). That will give you the number of seconds as an int

Then use java.time.Duration.ofSeconds() to create a java.time.Duration from that int.

import org.joda.time.format.PeriodFormatterBuilder
import org.joda.time.format.PeriodFormatter

PeriodFormatter formatter = new PeriodFormatterBuilder()
        .printZeroNever()
        .appendDays().appendSuffix("d")
        .appendHours().appendSuffix("h")
        .appendMinutes().appendSuffix("m")
        .appendSeconds().appendSuffix("s")
        .toFormatter();

Period myPeriod = formatter.parsePeriod("1d2h3m4s");

java.time.Duration myDuration = java.time.Duration.ofSeconds(
        myPeriod.toStandardSeconds().getSeconds());
RubenLaguna
  • 21,435
  • 13
  • 113
  • 151