human.nbt 3.0 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758
  1. use core::functions
  2. use core::strings
  3. use units::si
  4. use units::time
  5. use datetime::functions
  6. fn _human_join(a: String, b: String) -> String =
  7. if a == "" then b else if b == "" then a else "{a} + {b}"
  8. fn _prettier(str: String) -> String =
  9. if str_slice(clean_str, 0, 2) == "0 " then ""
  10. else if str_slice(clean_str, 0, 2) == "1 " then str_slice(clean_str, 0, str_length(clean_str) - 1)
  11. else clean_str
  12. where clean_str = str_replace(str, ".0 ", " ")
  13. fn _human_years(time: Time) -> String = "{(time -> years) / year |> floor} years" -> _prettier
  14. fn _human_months(time: Time) -> String = "{(time -> months) / month |> round} months" -> _prettier
  15. fn _human_days(time: Time) -> String = "{(time -> days) / day |> floor} days" -> _prettier
  16. fn _human_hours(time: Time) -> String = "{(time -> hours) / hour |> floor} hours" -> _prettier
  17. fn _human_minutes(time: Time) -> String = "{(time -> minutes) / minute |> floor} minutes" -> _prettier
  18. fn _precise_human_months(time: Time) -> String = "{(time -> months) / month } months" -> _prettier
  19. fn _precise_human_days(time: Time) -> String = "{(time -> days) / day } days" -> _prettier
  20. fn _precise_human_seconds(time: Time) -> String = "{(time -> seconds) / second} seconds" -> _prettier
  21. fn _human_recurse(t: Time, result: String, time_unit: String) -> String =
  22. if time_unit == "day"
  23. then _human_recurse((t -> day) - (t |> floor_in(day)), _human_join(result, t -> _human_days), "hour")
  24. else if time_unit == "hour"
  25. then _human_recurse((t -> hour) - (t |> floor_in(hour)), _human_join(result, t -> _human_hours), "minute")
  26. else if time_unit == "minute"
  27. then _human_recurse((t -> min) - (t |> floor_in(min)), _human_join(result, t -> _human_minutes), "second")
  28. else _human_join(result, (t |> round_in(ms)) -> _precise_human_seconds)
  29. fn _year_month_approx(t: Time) -> String = _human_join(the_years -> _human_years, t - the_years -> _human_months)
  30. where the_years = t |> floor_in(year)
  31. fn _human_manage_past(str: String, time: Time) = str_append(str, if time < 0 s then " ago" else "")
  32. fn _human_for_long_duration(human_days: String, human_years: String) -> String =
  33. "{human_days} (approx. {human_years})"
  34. fn _abs_human(time: Time) -> String =
  35. if time == 0 s then "0 seconds"
  36. else if time < 60 seconds then time -> _precise_human_seconds
  37. else if time < 2 months then _human_recurse(time, "", "day")
  38. else if time < 1 year
  39. then _human_for_long_duration(time -> _precise_human_days, (time |> round_in(month/10)) -> _precise_human_months)
  40. else if time < 100 years
  41. then _human_for_long_duration(time -> _precise_human_days, _year_month_approx(time))
  42. else
  43. _human_for_long_duration(time -> _precise_human_days, time -> _human_years)
  44. @name("Human-readable time duration")
  45. @url("https://numbat.dev/doc/date-and-time.html")
  46. @description("Converts a time duration to a human-readable string in days, hours, minutes and seconds.")
  47. fn human(time: Time) -> String = _human_manage_past(abs(time) -> _abs_human, time)