* minutes become "about 13 hours". The suffix can be used to describe the event's position in time, use e.g. " ago" or " from now"
*/
@Validate
public static String toHumanReadable(@NotNull final Duration ts, @NotNull final String suffix)
{
val values = new AvlHashtable<Double, String>(Double.class, String.class);
long totalSeconds = Math.abs(ts.getStandardSeconds());
final double totalMinutes = Math.round(totalSeconds / 60);
double totalHours = Math.round(totalMinutes / 60);
double totalDays = Math.floor(totalHours / 24);
double totalMonths = Math.floor(totalDays / 30);
double totalYears = Math.floor(totalMonths / 12);
values.add(0.75d, "less than a minute");
values.add(1.5d, "about a minute");
values.add(45d, String.format("%d minutes", (int) totalMinutes));
values.add(90d, "about an hour");
values.add(1440d, String.format("about %d hours", (int) totalHours)); // 60 * 24
values.add(2880d, "a day"); // 60 * 48
values.add(43200d, String.format("%d days", (int) totalDays)); // 60 * 24 * 30
values.add(86400d, "about a month"); // 60 * 24 * 60
values.add(525600d, String.format("%d months", (int) totalMonths)); // 60 * 24 * 365
values.add(1051200d, "about a year"); // 60 * 24 * 365 * 2
values.add(Double.MAX_VALUE, String.format("%d years", (int) totalYears));
Double key = Linq.first(values.getKeys(), keyGreaterThan(totalMinutes));
return values.get(key) + suffix;
}