|
| 1 | +package io.github.jy95.fds.common.functions; |
| 2 | + |
| 3 | +import com.ibm.icu.number.NumberFormatter; |
| 4 | +import com.ibm.icu.number.Precision; |
| 5 | +import com.ibm.icu.number.UnlocalizedNumberFormatter; |
| 6 | +import com.ibm.icu.util.MeasureUnit; |
| 7 | + |
| 8 | +import java.util.Locale; |
| 9 | +import java.util.Map; |
| 10 | + |
| 11 | +/** |
| 12 | + * Class to format units of time |
| 13 | + */ |
| 14 | +public final class UnitsOfTimeFormatter { |
| 15 | + |
| 16 | + /** |
| 17 | + * Map each code of <a href="https://build.fhir.org/valueset-units-of-time.html">Units of Time</a> to their ICU4J units |
| 18 | + */ |
| 19 | + private static final Map<String, MeasureUnit> UNIT_MAPPING = Map.ofEntries( |
| 20 | + Map.entry("ms", MeasureUnit.MILLISECOND), |
| 21 | + Map.entry("s", MeasureUnit.SECOND), |
| 22 | + Map.entry("min", MeasureUnit.MINUTE), |
| 23 | + Map.entry("h", MeasureUnit.HOUR), |
| 24 | + Map.entry("d", MeasureUnit.DAY), |
| 25 | + Map.entry("wk", MeasureUnit.WEEK), |
| 26 | + Map.entry("mo", MeasureUnit.MONTH), |
| 27 | + Map.entry("a", MeasureUnit.YEAR) |
| 28 | + ); |
| 29 | + |
| 30 | + /** |
| 31 | + * Common formatter for all calls to this class |
| 32 | + */ |
| 33 | + private static final UnlocalizedNumberFormatter formatter = NumberFormatter |
| 34 | + .with() |
| 35 | + .unitWidth(NumberFormatter.UnitWidth.FULL_NAME); |
| 36 | + |
| 37 | + /** |
| 38 | + * No constructor for this class |
| 39 | + */ |
| 40 | + private UnitsOfTimeFormatter() {} |
| 41 | + |
| 42 | + /** |
| 43 | + * Formats a time unit with a count (e.g., "3 heures", "1 minute"). |
| 44 | + * @param locale The locale expected for the resulting text |
| 45 | + * @param unit The <a href="https://build.fhir.org/valueset-units-of-time.html">unit code</a> |
| 46 | + * @param count The quantity |
| 47 | + * @return A formatted time-unit string with a count |
| 48 | + */ |
| 49 | + public static String formatWithCount(Locale locale, String unit, Number count) { |
| 50 | + return formatter |
| 51 | + .locale(locale) |
| 52 | + .unit(UNIT_MAPPING.get(unit)) |
| 53 | + .format(count) |
| 54 | + .toString(); |
| 55 | + } |
| 56 | + |
| 57 | + /** |
| 58 | + * Formats a time unit without a count (e.g., "heures", "minute"). |
| 59 | + * @param locale The locale expected for the resulting text |
| 60 | + * @param unit The <a href="https://build.fhir.org/valueset-units-of-time.html">unit code</a> |
| 61 | + * @param count The quantity |
| 62 | + * @return A formatted time-unit string without a count |
| 63 | + */ |
| 64 | + public static String formatWithoutCount(Locale locale, String unit, Number count) { |
| 65 | + // ICU4j doesn't have a method for extracting only the unit with plural form so a bit of magic here |
| 66 | + return formatter |
| 67 | + .unit(UNIT_MAPPING.get(unit)) |
| 68 | + .locale(locale) |
| 69 | + .precision(Precision.maxSignificantDigits(1)) |
| 70 | + .format(count) |
| 71 | + .toString() |
| 72 | + .substring(2); // 1 because of the number display + 1 because of spacing |
| 73 | + } |
| 74 | +} |
0 commit comments