org.aeonbits.owner.converters.DurationConverter Maven / Gradle / Ivy
/*
* Copyright (c) 2012-2016, Luigi R. Viggiano
* All rights reserved.
*
* This software is distributable under the BSD license.
* See the terms of the BSD license in the documentation provided with this software.
*/
package org.aeonbits.owner.converters;
import org.aeonbits.owner.Converter;
import java.lang.reflect.Method;
import java.time.Duration;
import java.time.temporal.ChronoUnit;
/**
* A duration converter for the OWNER configuration system.
*
* This converter will convert various duration formatted strings over to {@link java.time.Duration} objects.
*
* The class supports two formats for the duration string:
*
* -
* The ISO-8601 based format that the {@link java.time.Duration#parse(CharSequence)} method supports
* (see the official Java 8 documentation, although note that currently there is an
* error in the documentation).
* The implementation will check whether the input string starts with
P
with an optional plus/minus
* prefix and if so, will use this method for parsing.
*
* -
* A "
value time_unit
" string where the value
is an integer and time_unit
* is one of:
*
* - ns / nanos / nanoseconds
* - us / µs / micros / microseconds
* - ms / millis / milliseconds
* - s / seconds
* - m / minutes
* - h / hours
* - d / days
*
*
* Note that the time_unit
string is case sensitive.
*
* If no time_unit
is specified, milliseconds
is assumed.
*
*
*/
public class DurationConverter implements Converter {
@Override
public Duration convert(Method method, String input) {
// If it looks like a string that Duration.parse can handle, let's try that.
if (input.startsWith("P") || input.startsWith("-P") || input.startsWith("+P")) {
return Duration.parse(input);
}
// ...otherwise we'll perform our own parsing
return parseDuration(input);
}
/**
* Parses a duration string. If no units are specified in the string, it is
* assumed to be in milliseconds.
*
* This implementation was blatantly stolen/adapted from the typesafe-config project:
* https://github.com/typesafehub/config/blob/v1.3.0/config/src/main/java/com/typesafe/config/impl/SimpleConfig.java#L551-L624
*
* @param input the string to parse
* @return duration
* @throws IllegalArgumentException if input is invalid
*/
private static Duration parseDuration(String input) {
String[] parts = ConverterUtil.splitNumericAndChar(input);
String numberString = parts[0];
String originalUnitString = parts[1];
String unitString = originalUnitString;
if (numberString.length() == 0) {
throw new IllegalArgumentException(String.format("No number in duration value '%s'", input));
}
if (unitString.length() > 2 && !unitString.endsWith("s")) {
unitString = unitString + "s";
}
ChronoUnit units;
// note that this is deliberately case-sensitive
switch (unitString) {
case "ns":
case "nanos":
case "nanoseconds":
units = ChronoUnit.NANOS;
break;
case "us":
case "µs":
case "micros":
case "microseconds":
units = ChronoUnit.MICROS;
break;
case "":
case "ms":
case "millis":
case "milliseconds":
units = ChronoUnit.MILLIS;
break;
case "s":
case "seconds":
units = ChronoUnit.SECONDS;
break;
case "m":
case "minutes":
units = ChronoUnit.MINUTES;
break;
case "h":
case "hours":
units = ChronoUnit.HOURS;
break;
case "d":
case "days":
units = ChronoUnit.DAYS;
break;
default:
throw new IllegalArgumentException(
String.format("Could not parse time unit '%s' (try ns, us, ms, s, m, h, d)", originalUnitString));
}
return Duration.of(Long.parseLong(numberString), units);
}
private static String getUnits(String s) {
int i = s.length() - 1;
while (i >= 0) {
char c = s.charAt(i);
if (!Character.isLetter(c))
break;
i -= 1;
}
return s.substring(i + 1);
}
}