I want to convert "08:30:00" into P00DT08H30M. what is the best way to convert to the desired output in java?
-
If the value is "2:00:30:00" then the output should be like P02DT00H30M.. – sub Apr 20 '18 at 13:36
-
You seem to be asking for someone to write some code for you. Stack Overflow is a question and answer site, not a code-writing service. Please [see here](http://stackoverflow.com/help/how-to-ask) to learn how to write effective questions. – lexicore Apr 20 '18 at 13:40
-
Possible duplicate of [Java string to date conversion](https://stackoverflow.com/questions/4216745/java-string-to-date-conversion) – Apr 20 '18 at 13:40
-
2@Codeer Is it? This question is about parsing something into duration, not a date. – lexicore Apr 20 '18 at 13:42
6 Answers
P00DT08H30M
is the ISO8601's format for durations. It represents a span of elapsed time - in this case: "8 hours and 30 minutes".
Note that it's not a time of the day - it's not the same thing as "8:30 AM". A time of the day represents a specific moment of the day: 08:30 (either AM or PM), is a specific moment. While a duration (8 hours and 30 minutes) represents a span of elapsed time, no matter when it starts or ends.
What might confuse people is that both uses the same words ("minutes", "seconds", etc), and can even be represented the same way ("I have a meeting at 08:30 AM" or "The duration of the event is 08:30 hours") but they are different concepts.
Anyway, one solution is to use lots of substring
combined with concatenation, as the other answers suggested. But you can also use JSR 310 classes: in Java 8 they are in java.time
packaged, and in older versions you can find them in the ThreeTen-Backport library.
In both, there are some alternatives:
You can split the string and use the parts to build a Duration
:
String s = "08:30:00";
String[] parts = s.split(":");
Duration duration = Duration.ofHours(Long.parseLong(parts[0]))
.plusMinutes(Long.parseLong(parts[1]))
.plusSeconds(Long.parseLong(parts[2]));
String output = duration.toString();
Or you can use the (conceptually incorrect) approach of pretending that the input is a time of the day, and calculate the difference between this time and midnight:
LocalTime time = LocalTime.parse("08:30:00");
Duration duration = Duration.between(LocalTime.MIDNIGHT, time);
String output = duration.toString();
But note that the duration.toString()
method omits all the fields that are zero, and the output will be PT8H30M
. But you can overcome this by using a simple replace:
System.out.println(output.replace("PT", "P00DT"));
This prints:
P00DT8H30M
Also note that the "8" is not padded with a zero (it doesn't print it as "08"). Not sure if it makes difference to you.
The second approach "works" only if you have time fields (hours, minutes and seconds). For the other case you mentioned in the comments:
If the value is "2:00:30:00" then the output should be like P02DT00H30M
Then it's better to use the first approach. Perhaps you can check how many parts the input has and set the fields accordingly. But the Duration
class converts the days to hours, so to get the output you want, you'll need the ThreeTen-Extra projectand its PeriodDuration
class:
String s = "2:00:30:00";
String[] parts = s.split(":");
int days = 0;
long hours = 0, minutes = 0, seconds = 0;
if (parts.length == 3) {
hours = Long.parseLong(parts[0]);
minutes = Long.parseLong(parts[1]);
seconds = Long.parseLong(parts[2]);
} else if (parts.length == 4) {
days = Integer.parseInt(parts[0]);
hours = Long.parseLong(parts[1]);
minutes = Long.parseLong(parts[2]);
seconds = Long.parseLong(parts[3]);
} // and add more cases for different lengths
Duration duration = Duration.ofHours(hours)
.plusMinutes(minutes)
.plusSeconds(seconds);
PeriodDuration pd = PeriodDuration.of(Period.ofDays(days), duration);
String output = pd.toString();
But again, all the fields with value zero will be ommited, so it'll require a post-processing of the output. But I think quite redundant to print all the zeroes fields - unless it's a must-have requirement of your system.

- 303,325
- 100
- 852
- 1,154

- 21
- 1
-
1Excellent answer, explaining difference between time-of-day and duration. – Basil Bourque Apr 20 '18 at 21:52
-
Small correction: `java.time.Duration` converts days to seconds, not to hours (on the base of 1 day = 86400 seconds) because its internal state can ONLY represent seconds and nanoseconds. – Meno Hochschild Apr 24 '18 at 12:07
Since your desired result, P00DT08H30M
, conforms with the ISO 8601 format for a duration, I am assuming that your 08:30:00
is exactly that: a duration, an amount of time. 8 hours 30 minutes (0 seconds).
There are a number of options each with their pros and cons. I think I would go for this one:
String durationString = "08:30:00";
Pattern durationPattern = Pattern.compile("(\\d{2,}):([0-5]\\d):([0-5]\\d)");
Matcher m = durationPattern.matcher(durationString);
if (m.matches()) {
Duration dur = Duration.ofHours(Long.parseLong(m.group(1)))
.plusMinutes(Long.parseLong(m.group(2)))
.plusSeconds(Long.parseLong(m.group(3)));
System.out.println(dur);
}
Output:
PT8H30M
Pro: The regular expression validates the string. In my code I have required hours in at least two digits and minutes and seconds in the interval 00–59, in two digits each. You can adjust the regular expression to the validation that is right for your situation. I like having the validation since the Duration
class itself doesn’t seem to offer one.
I am parsing into a Duration
object. I think this is what you should want to do in most situations. The output is the result of Duration.toString()
. It’s not exactly the string you asked for, but for most purposes this should be OK since it is ISO 8601, so should be accepted where you use it. At the bottom I will show how to format the Duration
object into exactly the string you mentioned in case you insist.
The construction of the Duration
object from the parsed regular expression can be made a line shorter:
String durText = "PT" + m.group(1) + "H" + m.group(2) + "M" + m.group(3) + "S";
Duration dur = Duration.parse(durText);
Pro: A line shorter.
Con: Now we’re really parsing the duration twice, and the reader will wonder whether this was really necessary.
A simpler way of getting the parts from the original string is String.split()
:
String[] parts = durationString.split(":");
if (parts.length == 3) {
Duration dur = Duration.ofHours(Long.parseLong(parts[0]))
.plusMinutes(Long.parseLong(parts[1]))
.plusSeconds(Long.parseLong(parts[2]));
System.out.println(dur);
}
Pros: (1) Simpler. (2) It’s fairly easy to allow just two parts separated by a colon. But think twice before you decide whether that means hours:minutes or minutes:seconds. Also four parts days:hours:minutes:seconds as mentioned in your other example can be accommodated with a minor change.
Con: No input validation beyond it’s three numbers separated by colons.
Again you may assemble a new string and parse it with Duration.parse
to save a line.
Finally there’s the cheating: use a LocalTime
.
LocalTime time = LocalTime.parse(durationString);
Duration dur = Duration.between(LocalTime.MIN, time);
Pros: (1) Really short and simple. (2) Includes validation (allows omitted seconds or fractional seconds though; 08:30
and 08:31:32.4567789
are OK).
Cons: (1) Misusing LocalTime
, a time of day, for a duration, which conceptually is a completely different story. This means confusion. (2) Doesn’t allow a duration longer than 23 hours 59 minutes 59 seconds, which is really absurd. Not least when your desired output also has room for two-digit days.
Formatting
In Java 9 and later, if you insist on the exact output format P00DT08H30M
:
String formattedDuration = String.format(Locale.ROOT, "P%02dDT%02dH%02dM",
dur.toDays(), dur.toHoursPart(), dur.toMinutesPart());
System.out.println(formattedDuration);
Output:
P00DT08H30M
Your requested format didn’t include seconds, so I am not outputting any even if there are some.

- 81,772
- 15
- 137
- 161
Using my lib Time4J, the simplest solution would use a pattern-based approach, one pattern for parsing and another one for printing:
String d1 = "08:30:00";
String d2 = "2:00:30:00";
Duration.Formatter<IsoUnit> parser = Duration.formatter("[#D:]hh:mm:ss");
Duration.Formatter<IsoUnit> printer = Duration.formatter("'P'DD'DT'hh'H'mm'M'");
System.out.println(printer.format(parser.parse(d1))); // P00DT08H30M
System.out.println(printer.format(parser.parse(d2))); // P02DT00H30M
The suggested solution also prints zero components. I don't know if you have second parts which are non-zero, so I have ignored it in printing (according to your desired output).
What the other answers say about the conceptual difference between "time-of-day" and "duration" is mostly correct so I hope you are already aware of this. However, even ISO-8601 knows an alternative syntax for representing durations where it is legal to print "P0000-00-02T00:30" instead of "P02DT00H30M". Such expressions are still durations and NOT points in time because of the leading "P".

- 42,708
- 7
- 104
- 126
If its a text, you can do something like:
String output = "P00DT" + test.substring(0,2) + "H" + test.substring(3,5) + "M";

- 425
- 2
- 4
- 19
String myString = "08:30:00";
String[] tokens = myString.split(":");
String myStringConverted = "P00DT"+tokens[0]+"H"+tokens[1]+"M"