/** * Obtains a {@code PeriodFields} from an amount and unit, by extending any fractional remainder * onto smaller units. * * <p>The parameters represent the two parts of a phrase like 'one-and-a-half Hours'. The * fractional parts will be distributed into the smaller units, and rounded down when no smaller * units exist. If the {@code fractionalAmount} is negative, the amount of the biggest unit will * be negative, the rest will be positive. * * @param fractionalAmount the amount of create with, positive or negative * @param unit the period unit, not null * @return the {@code PeriodFields} instance, not null */ public static PeriodFields of(double fractionalAmount, PeriodUnit unit) { checkNotNull(unit, "PeriodUnit must not be null"); PeriodUnit currentUnit = unit; double fudge = 0.000000000000001d; TreeMap<PeriodUnit, PeriodField> internalMap = createMap(); do { long floor = (long) Math.floor(fractionalAmount + fudge); if (floor != 0) { internalMap.put(currentUnit, PeriodField.of(floor, currentUnit)); } double remainder = fractionalAmount - floor; // will be positive PeriodField nextEquivalent = currentUnit.getNextEquivalentPeriod(); if (nextEquivalent != null) { currentUnit = nextEquivalent.getUnit(); fractionalAmount = remainder * nextEquivalent.getAmount(); fudge *= nextEquivalent.getAmount(); } else { // No smaller units exist, we're done currentUnit = null; } } while (currentUnit != null && Math.abs(fractionalAmount) > fudge); if (internalMap.isEmpty()) { return of(0L, unit); } else { return create(internalMap); } }