Skip to content

Commit 07503c2

Browse files
authored
Allow extended unit names for days, hours, minutes, seconds, milliseconds and allow spaces before the unit in expire duration parser (#4873)
* Allow extended unit names for days, hours, minutes, seconds, milliseconds in expire duration parser Signed-off-by: Jimmy Tanagra <jcode@tanagra.id.au>
1 parent a010cdb commit 07503c2

2 files changed

Lines changed: 68 additions & 15 deletions

File tree

bundles/org.openhab.core/src/main/java/org/openhab/core/util/DurationUtils.java

Lines changed: 54 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -27,20 +27,64 @@
2727
@NonNullByDefault
2828
public class DurationUtils {
2929

30-
private static final Pattern DURATION_PATTERN = Pattern.compile(
31-
"(?:([0-9]+)D)?\\s*(?:([0-9]+)H)?\\s*(?:([0-9]+)M)?\\s*(?:([0-9]+)S)?\\s*(?:([0-9]+)MS)?",
32-
Pattern.CASE_INSENSITIVE);
30+
private static final Pattern DURATION_PATTERN = Pattern.compile("""
31+
(?:([0-9]+)\\s*(?:d|days?))?
32+
\\s*
33+
(?:([0-9]+)\\s*(?:h|hrs?|hours?))?
34+
\\s*
35+
(?:([0-9]+)\\s*(?:m|mins?|minutes?))?
36+
\\s*
37+
(?:([0-9]+)\\s*(?:s|secs?|seconds?))?
38+
\\s*
39+
(?:([0-9]+)\\s*(?:ms|milliseconds?))?
40+
""", Pattern.CASE_INSENSITIVE | Pattern.COMMENTS);
41+
3342
private static final ChronoUnit[] DURATION_UNITS = { ChronoUnit.DAYS, ChronoUnit.HOURS, ChronoUnit.MINUTES,
3443
ChronoUnit.SECONDS, ChronoUnit.MILLIS };
3544

3645
/**
37-
* Parses a duration string in ISO-8601 format or a custom format like
38-
* "1d 1h 15m 30s 500ms" where
39-
* 'd' stands for days,
40-
* 'h' for hours,
41-
* 'm' for minutes,
42-
* 's' for seconds, and
43-
* 'ms' for milliseconds.
46+
* Parses a duration string in ISO-8601 duration format or a custom format like
47+
* "1d 1h 15m 30s 500ms".
48+
*
49+
* When specifying a duration, the units must be specified in the order of
50+
* days, hours, minutes, seconds, and milliseconds,
51+
* although any individual unit may be omitted.
52+
* Each unit must be preceded by an integer value.
53+
* A space between the number and its corresponding unit is permitted but not required.
54+
* Likewise, whitespace between unit groups is optional.
55+
*
56+
* The units supported in the duration format are:
57+
* <ul>
58+
* <li>'d|day|days' for days,
59+
* <li>'h|hr|hrs|hour|hours' for hours,
60+
* <li>'m|min|mins|minute|minutes' for minutes,
61+
* <li>'s|sec|secs|second|seconds' for seconds, and
62+
* <li>'ms|millisecond|milliseconds' for milliseconds.
63+
* </ul>
64+
*
65+
* Examples of valid duration strings:
66+
* <ul>
67+
* <li>"1h" represents 1 hour
68+
* <li>"15m" represents 15 minutes
69+
* <li>"1h15m" represents 1 day and 15 minutes. It can also be written as "1h 15m", "1 h 15 m", "1 hr 15 mins",
70+
* "1hour 15 minutes", etc.
71+
* <li>"1d 1h 30s" represents 1 day, 1 hour, and 30 seconds
72+
* </ul>
73+
*
74+
* The ISO-8601 duration format is supported, but only the following units are recognized:
75+
* days, hours, minutes, and seconds.
76+
* Units such as years, months, and weeks are not supported.
77+
* The number of days, hours and minutes must parse to a long.
78+
* The number of seconds must parse to a long with optional fraction.
79+
* The decimal point may be either a dot or a comma.
80+
* The fractional part may have from zero to 9 digits.
81+
*
82+
* Examples of ISO-8601 durations:
83+
* <ul>
84+
* <li>"PT1H30M" represents 1 hour and 30 minutes
85+
* <li>"PT1D" represents 1 day
86+
* <li>"PT0.5S" represents 0.5 seconds (500 milliseconds)
87+
* </ul>
4488
*
4589
* @param durationString the string representation of the duration
4690
* @return a Duration object representing the parsed duration

bundles/org.openhab.core/src/test/java/org/openhab/core/util/DurationUtilsTest.java

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -39,16 +39,25 @@ public void testParseISO8601() {
3939
assertEquals(3661000, DurationUtils.parse("PT1H1M1S").toMillis());
4040
}
4141

42+
private void testUnitCombinations(long expectedMillis, String number, String... units) {
43+
for (String unit : units) {
44+
assertEquals(expectedMillis, DurationUtils.parse(number + unit).toMillis());
45+
assertEquals(expectedMillis, DurationUtils.parse(number + " " + unit).toMillis());
46+
}
47+
}
48+
4249
@Test
4350
public void testParseCustom() {
44-
assertEquals(350, DurationUtils.parse("350ms").toMillis());
45-
assertEquals(1000, DurationUtils.parse("1s").toMillis());
46-
assertEquals(60000, DurationUtils.parse("1m").toMillis());
47-
assertEquals(3600000, DurationUtils.parse("1h").toMillis());
48-
assertEquals(86400000, DurationUtils.parse("1d").toMillis());
51+
testUnitCombinations(350, "350", "ms", "millisecond", "milliseconds");
52+
testUnitCombinations(1000, "1", "s", "sec", "secs", "second", "seconds");
53+
testUnitCombinations(60000, "1", "m", "min", "mins", "minute", "minutes");
54+
testUnitCombinations(3600000, "1", "h", "hr", "hrs", "hour", "hours");
55+
testUnitCombinations(86400000, "1", "d", "day", "days");
4956

5057
// Mixed units
5158
assertEquals(61000, DurationUtils.parse("1m 1s").toMillis());
59+
assertEquals(61000, DurationUtils.parse("1 m 1 s").toMillis());
60+
assertEquals(61000, DurationUtils.parse("1 min 1 sec").toMillis());
5261
assertEquals(3661000, DurationUtils.parse("1h 1m 1s").toMillis());
5362
assertEquals(3661000, DurationUtils.parse("1h1m1s").toMillis());
5463
}

0 commit comments

Comments
 (0)