Polishing
Backport Bot / build (push) Has been cancelled
Details
Build and Deploy Snapshot / Build and Deploy Snapshot (push) Has been cancelled
Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:false version:17], map[id:ubuntu-latest name:Linux]) (push) Has been cancelled
Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:true version:21], map[id:ubuntu-latest name:Linux]) (push) Has been cancelled
Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:true version:23], map[id:ubuntu-latest name:Linux]) (push) Has been cancelled
Details
Deploy Docs / Dispatch docs deployment (push) Has been cancelled
Details
Build and Deploy Snapshot / Verify (push) Has been cancelled
Details
Backport Bot / build (push) Has been cancelled
Details
Build and Deploy Snapshot / Build and Deploy Snapshot (push) Has been cancelled
Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:false version:17], map[id:ubuntu-latest name:Linux]) (push) Has been cancelled
Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:true version:21], map[id:ubuntu-latest name:Linux]) (push) Has been cancelled
Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:true version:23], map[id:ubuntu-latest name:Linux]) (push) Has been cancelled
Details
Deploy Docs / Dispatch docs deployment (push) Has been cancelled
Details
Build and Deploy Snapshot / Verify (push) Has been cancelled
Details
This commit is contained in:
parent
978590161a
commit
15364cf59f
|
@ -53,11 +53,19 @@ public @interface DurationFormat {
|
||||||
*/
|
*/
|
||||||
Unit defaultUnit() default Unit.MILLIS;
|
Unit defaultUnit() default Unit.MILLIS;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@link Duration} format styles.
|
* {@link Duration} format styles.
|
||||||
*/
|
*/
|
||||||
enum Style {
|
enum Style {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ISO-8601 formatting.
|
||||||
|
* <p>This is what the JDK uses in {@link Duration#parse(CharSequence)}
|
||||||
|
* and {@link Duration#toString()}.
|
||||||
|
*/
|
||||||
|
ISO8601,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Simple formatting based on a short suffix, for example '1s'.
|
* Simple formatting based on a short suffix, for example '1s'.
|
||||||
* <p>Supported unit suffixes include: {@code ns, us, ms, s, m, h, d}.
|
* <p>Supported unit suffixes include: {@code ns, us, ms, s, m, h, d}.
|
||||||
|
@ -72,13 +80,6 @@ public @interface DurationFormat {
|
||||||
*/
|
*/
|
||||||
SIMPLE,
|
SIMPLE,
|
||||||
|
|
||||||
/**
|
|
||||||
* ISO-8601 formatting.
|
|
||||||
* <p>This is what the JDK uses in {@link Duration#parse(CharSequence)}
|
|
||||||
* and {@link Duration#toString()}.
|
|
||||||
*/
|
|
||||||
ISO8601,
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Like {@link #SIMPLE}, but allows multiple segments ordered from
|
* Like {@link #SIMPLE}, but allows multiple segments ordered from
|
||||||
* largest-to-smallest units of time, like {@code 1h12m27s}.
|
* largest-to-smallest units of time, like {@code 1h12m27s}.
|
||||||
|
@ -90,6 +91,7 @@ public @interface DurationFormat {
|
||||||
COMPOSITE
|
COMPOSITE
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@link Duration} format unit, which mirrors a subset of {@link ChronoUnit} and
|
* {@link Duration} format unit, which mirrors a subset of {@link ChronoUnit} and
|
||||||
* allows conversion to and from a supported {@code ChronoUnit} as well as
|
* allows conversion to and from a supported {@code ChronoUnit} as well as
|
||||||
|
@ -227,7 +229,6 @@ public @interface DurationFormat {
|
||||||
}
|
}
|
||||||
throw new IllegalArgumentException("'" + suffix + "' is not a valid simple duration Unit");
|
throw new IllegalArgumentException("'" + suffix + "' is not a valid simple duration Unit");
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,6 +28,7 @@ import org.springframework.util.StringUtils;
|
||||||
/**
|
/**
|
||||||
* Support {@code Duration} parsing and printing in several styles, as listed in
|
* Support {@code Duration} parsing and printing in several styles, as listed in
|
||||||
* {@link DurationFormat.Style}.
|
* {@link DurationFormat.Style}.
|
||||||
|
*
|
||||||
* <p>Some styles may not enforce any unit to be present, defaulting to {@code DurationFormat.Unit#MILLIS}
|
* <p>Some styles may not enforce any unit to be present, defaulting to {@code DurationFormat.Unit#MILLIS}
|
||||||
* in that case. Methods in this class offer overloads that take a {@link DurationFormat.Unit} to
|
* in that case. Methods in this class offer overloads that take a {@link DurationFormat.Unit} to
|
||||||
* be used as a fall-back instead of the ultimate MILLIS default.
|
* be used as a fall-back instead of the ultimate MILLIS default.
|
||||||
|
@ -39,8 +40,38 @@ import org.springframework.util.StringUtils;
|
||||||
*/
|
*/
|
||||||
public abstract class DurationFormatterUtils {
|
public abstract class DurationFormatterUtils {
|
||||||
|
|
||||||
private DurationFormatterUtils() {
|
private static final Pattern ISO_8601_PATTERN = Pattern.compile("^[+-]?[pP].*$");
|
||||||
// singleton
|
|
||||||
|
private static final Pattern SIMPLE_PATTERN = Pattern.compile("^([+-]?\\d+)([a-zA-Z]{0,2})$");
|
||||||
|
|
||||||
|
private static final Pattern COMPOSITE_PATTERN = Pattern.compile("^([+-]?)\\(?\\s?(\\d+d)?\\s?(\\d+h)?\\s?(\\d+m)?" +
|
||||||
|
"\\s?(\\d+s)?\\s?(\\d+ms)?\\s?(\\d+us)?\\s?(\\d+ns)?\\)?$");
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Print the specified duration in the specified style.
|
||||||
|
* @param value the value to print
|
||||||
|
* @param style the style to print in
|
||||||
|
* @return the printed result
|
||||||
|
*/
|
||||||
|
public static String print(Duration value, DurationFormat.Style style) {
|
||||||
|
return print(value, style, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Print the specified duration in the specified style using the given unit.
|
||||||
|
* @param value the value to print
|
||||||
|
* @param style the style to print in
|
||||||
|
* @param unit the unit to use for printing, if relevant ({@code null} will default
|
||||||
|
* to ms)
|
||||||
|
* @return the printed result
|
||||||
|
*/
|
||||||
|
public static String print(Duration value, DurationFormat.Style style, @Nullable DurationFormat.Unit unit) {
|
||||||
|
return switch (style) {
|
||||||
|
case ISO8601 -> value.toString();
|
||||||
|
case SIMPLE -> printSimple(value, unit);
|
||||||
|
case COMPOSITE -> printComposite(value);
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -71,29 +102,24 @@ public abstract class DurationFormatterUtils {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Print the specified duration in the specified style.
|
* Detect the style from the given source value.
|
||||||
* @param value the value to print
|
* @param value the source value
|
||||||
* @param style the style to print in
|
* @return the duration style
|
||||||
* @return the printed result
|
* @throws IllegalArgumentException if the value is not a known style
|
||||||
*/
|
*/
|
||||||
public static String print(Duration value, DurationFormat.Style style) {
|
public static DurationFormat.Style detect(String value) {
|
||||||
return print(value, style, null);
|
Assert.notNull(value, "Value must not be null");
|
||||||
}
|
// warning: the order of parsing starts to matter if multiple patterns accept a plain integer (no unit suffix)
|
||||||
|
if (ISO_8601_PATTERN.matcher(value).matches()) {
|
||||||
/**
|
return DurationFormat.Style.ISO8601;
|
||||||
* Print the specified duration in the specified style using the given unit.
|
}
|
||||||
* @param value the value to print
|
if (SIMPLE_PATTERN.matcher(value).matches()) {
|
||||||
* @param style the style to print in
|
return DurationFormat.Style.SIMPLE;
|
||||||
* @param unit the unit to use for printing, if relevant ({@code null} will default
|
}
|
||||||
* to ms)
|
if (COMPOSITE_PATTERN.matcher(value).matches()) {
|
||||||
* @return the printed result
|
return DurationFormat.Style.COMPOSITE;
|
||||||
*/
|
}
|
||||||
public static String print(Duration value, DurationFormat.Style style, @Nullable DurationFormat.Unit unit) {
|
throw new IllegalArgumentException("'" + value + "' is not a valid duration, cannot detect any known style");
|
||||||
return switch (style) {
|
|
||||||
case ISO8601 -> value.toString();
|
|
||||||
case SIMPLE -> printSimple(value, unit);
|
|
||||||
case COMPOSITE -> printComposite(value);
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -120,31 +146,6 @@ public abstract class DurationFormatterUtils {
|
||||||
return parse(value, detect(value), unit);
|
return parse(value, detect(value), unit);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Detect the style from the given source value.
|
|
||||||
* @param value the source value
|
|
||||||
* @return the duration style
|
|
||||||
* @throws IllegalArgumentException if the value is not a known style
|
|
||||||
*/
|
|
||||||
public static DurationFormat.Style detect(String value) {
|
|
||||||
Assert.notNull(value, "Value must not be null");
|
|
||||||
// warning: the order of parsing starts to matter if multiple patterns accept a plain integer (no unit suffix)
|
|
||||||
if (ISO_8601_PATTERN.matcher(value).matches()) {
|
|
||||||
return DurationFormat.Style.ISO8601;
|
|
||||||
}
|
|
||||||
if (SIMPLE_PATTERN.matcher(value).matches()) {
|
|
||||||
return DurationFormat.Style.SIMPLE;
|
|
||||||
}
|
|
||||||
if (COMPOSITE_PATTERN.matcher(value).matches()) {
|
|
||||||
return DurationFormat.Style.COMPOSITE;
|
|
||||||
}
|
|
||||||
throw new IllegalArgumentException("'" + value + "' is not a valid duration, cannot detect any known style");
|
|
||||||
}
|
|
||||||
|
|
||||||
private static final Pattern ISO_8601_PATTERN = Pattern.compile("^[+-]?[pP].*$");
|
|
||||||
private static final Pattern SIMPLE_PATTERN = Pattern.compile("^([+-]?\\d+)([a-zA-Z]{0,2})$");
|
|
||||||
private static final Pattern COMPOSITE_PATTERN = Pattern.compile("^([+-]?)\\(?\\s?(\\d+d)?\\s?(\\d+h)?\\s?(\\d+m)?" +
|
|
||||||
"\\s?(\\d+s)?\\s?(\\d+ms)?\\s?(\\d+us)?\\s?(\\d+ns)?\\)?$");
|
|
||||||
|
|
||||||
private static Duration parseIso8601(String value) {
|
private static Duration parseIso8601(String value) {
|
||||||
try {
|
try {
|
||||||
|
@ -155,6 +156,11 @@ public abstract class DurationFormatterUtils {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static String printSimple(Duration duration, @Nullable DurationFormat.Unit unit) {
|
||||||
|
unit = (unit == null ? DurationFormat.Unit.MILLIS : unit);
|
||||||
|
return unit.print(duration);
|
||||||
|
}
|
||||||
|
|
||||||
private static Duration parseSimple(String text, @Nullable DurationFormat.Unit fallbackUnit) {
|
private static Duration parseSimple(String text, @Nullable DurationFormat.Unit fallbackUnit) {
|
||||||
try {
|
try {
|
||||||
Matcher matcher = SIMPLE_PATTERN.matcher(text);
|
Matcher matcher = SIMPLE_PATTERN.matcher(text);
|
||||||
|
@ -171,34 +177,6 @@ public abstract class DurationFormatterUtils {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static String printSimple(Duration duration, @Nullable DurationFormat.Unit unit) {
|
|
||||||
unit = (unit == null ? DurationFormat.Unit.MILLIS : unit);
|
|
||||||
return unit.print(duration);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static Duration parseComposite(String text) {
|
|
||||||
try {
|
|
||||||
Matcher matcher = COMPOSITE_PATTERN.matcher(text);
|
|
||||||
Assert.state(matcher.matches() && matcher.groupCount() > 1, "Does not match composite duration pattern");
|
|
||||||
String sign = matcher.group(1);
|
|
||||||
boolean negative = sign != null && sign.equals("-");
|
|
||||||
|
|
||||||
Duration result = Duration.ZERO;
|
|
||||||
DurationFormat.Unit[] units = DurationFormat.Unit.values();
|
|
||||||
for (int i = 2; i < matcher.groupCount() + 1; i++) {
|
|
||||||
String segment = matcher.group(i);
|
|
||||||
if (StringUtils.hasText(segment)) {
|
|
||||||
DurationFormat.Unit unit = units[units.length - i + 1];
|
|
||||||
result = result.plus(unit.parse(segment.replace(unit.asSuffix(), "")));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return negative ? result.negated() : result;
|
|
||||||
}
|
|
||||||
catch (Exception ex) {
|
|
||||||
throw new IllegalArgumentException("'" + text + "' is not a valid composite duration", ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static String printComposite(Duration duration) {
|
private static String printComposite(Duration duration) {
|
||||||
if (duration.isZero()) {
|
if (duration.isZero()) {
|
||||||
return DurationFormat.Unit.SECONDS.print(duration);
|
return DurationFormat.Unit.SECONDS.print(duration);
|
||||||
|
@ -243,4 +221,27 @@ public abstract class DurationFormatterUtils {
|
||||||
return result.toString();
|
return result.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static Duration parseComposite(String text) {
|
||||||
|
try {
|
||||||
|
Matcher matcher = COMPOSITE_PATTERN.matcher(text);
|
||||||
|
Assert.state(matcher.matches() && matcher.groupCount() > 1, "Does not match composite duration pattern");
|
||||||
|
String sign = matcher.group(1);
|
||||||
|
boolean negative = sign != null && sign.equals("-");
|
||||||
|
|
||||||
|
Duration result = Duration.ZERO;
|
||||||
|
DurationFormat.Unit[] units = DurationFormat.Unit.values();
|
||||||
|
for (int i = 2; i < matcher.groupCount() + 1; i++) {
|
||||||
|
String segment = matcher.group(i);
|
||||||
|
if (StringUtils.hasText(segment)) {
|
||||||
|
DurationFormat.Unit unit = units[units.length - i + 1];
|
||||||
|
result = result.plus(unit.parse(segment.replace(unit.asSuffix(), "")));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return negative ? result.negated() : result;
|
||||||
|
}
|
||||||
|
catch (Exception ex) {
|
||||||
|
throw new IllegalArgumentException("'" + text + "' is not a valid composite duration", ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue