public class DurationParser {
// (unit prefix, int-to-duration converter)
private static final Map<String, IntFunction<TemporalAmount>> UNITS;
static {
final ImmutableMap.Builder<String, IntFunction<TemporalAmount>> builder = ImmutableMap.builder();
final BiConsumer<IntFunction<TemporalAmount>, Iterator<String>> registry = (converter, suffixes) -> suffixes.forEachRemaining(suffix -> builder.put(suffix, converter));
final BiConsumer<TemporalUnit, Iterator<String>> temporalUnit = (unit, suffixes) -> registry.accept((d) -> unit.getDuration().multipliedBy(d), suffixes);
// Modifier les unités ici
temporalUnit.accept(ChronoUnit.SECONDS, Iterators.forArray("s", "second, seconds"));
temporalUnit.accept(ChronoUnit.MINUTES, Iterators.forArray("m", "mn", "min", "minute", "minutes"));
temporalUnit.accept(ChronoUnit.HOURS, Iterators.forArray("h", "hour", "hours"));
temporalUnit.accept(ChronoUnit.DAYS, Iterators.forArray("d", "day", "days"));
temporalUnit.accept(ChronoUnit.MONTHS, Iterators.forArray("mt", "month", "months"));
temporalUnit.accept(ChronoUnit.YEARS, Iterators.forArray("y", "year", "years"));
UNITS = builder.build();
for(String suffix : UNITS.keySet()) {
if(suffix == null || suffix.isEmpty() || Character.digit(suffix.charAt(0), 10) >= 0) {
throw new IllegalArgumentException("Suffixes must starts with a non-digit: " + suffix);
}
}
}
/**
* Transforme la chaîne de caractères passée en argument en une {@link Duration}.
*
* @param str la chaîne à convertir
* @return la durée convertie
* @throws ParseException si une unité de temps n'est pas reconnue, qu'un nombre
* est présent sans unité, ou que la chaîne ne commence pas par un chiffre
* @throws ArithmeticException en cas de dépassement numérique
*/
@CheckReturnValue
public static Duration parse(String str) throws ParseException {
// the sum of all time (quantity, unit) pairs
Duration sum = Duration.ZERO;
if(str == null || str.isEmpty()) {
return sum; // duh.
}
// in the case you want to write your quantities in base 2.
// note that radix > 10 will collide with a- unit suffixes.
final int radix = 10;
char c = str.charAt(0);
int digit = Character.digit(c, radix);
if(digit < 0) {
throw new ParseException("Expecting a digit, got a character", 0);
}
// the current time quantity
int value = digit;
// the current time unit
StringBuilder suffix = new StringBuilder();
for(int i = 1; i < str.length(); ++i) {
c = str.charAt(i);
digit = Character.digit(c, radix);
if(digit >= 0) {
// if we got a digit after some characters,
// push the current (quantity, unit) to the sum
if(suffix.length() != 0) {
sum = pushTemporalPair(sum, value, suffix, i);
value = digit;
suffix.setLength(0);
}
else {
// else add the current digit to the current quantity
value = Math.addExact(Math.multiplyExact(value, radix), digit);
}
}
else {
// we got a non-digit character
suffix.append(c);
}
}
if(suffix.length() != 0) {
// push the last (quantity, unit) pair
sum = pushTemporalPair(sum, value, suffix, str.length());
}
else if(value != 0) {
throw new ParseException("Got " + value + " without a time unit.", str.length());
}
return sum;
}
@CheckReturnValue
private static TemporalAmount parseTemporalUnit(int value, @NotNull String suffix, int offset) throws ParseException {
var converter = UNITS.get(suffix);
if(converter == null) {
throw new ParseException("Unknown time unit: " + suffix, offset - suffix.length());
}
return converter.apply(value);
}
@CheckReturnValue
private static Duration pushTemporalPair(@NotNull Duration sum, int value, @NotNull StringBuilder suffix, int offset) throws ParseException {
return sum.plus(Duration.from(parseTemporalUnit(value, suffix.toString(), offset)));
}
}