From b666758a546c6667254a2ef26702eb0c4647eebe Mon Sep 17 00:00:00 2001 From: Cooldude2606 <25043174+Cooldude2606@users.noreply.github.com> Date: Sun, 19 Jan 2025 23:47:22 +0000 Subject: [PATCH] Fix time format with nil plural --- exp_util/module/module_exports.lua | 151 +++++++++++++++-------------- 1 file changed, 77 insertions(+), 74 deletions(-) diff --git a/exp_util/module/module_exports.lua b/exp_util/module/module_exports.lua index c4749a5d..f7059c5f 100644 --- a/exp_util/module/module_exports.lua +++ b/exp_util/module/module_exports.lua @@ -247,8 +247,6 @@ function ExpUtil.format_any(value, options) end --- @alias Common.format_time_param_format "short" | "long" | "clock" --- TODO a single common function for calculating units for format_time and format_time_locale --- TODO fix nil times because {"days", "--"} is not a valid locale string --- @class Common.format_time_param_units --- @field days boolean? True if days are included @@ -256,55 +254,78 @@ end --- @field minutes boolean? True if minutes are included --- @field seconds boolean? True if seconds are included +--- @class Common.extract_time_units_return +--- @field days number? Amount of days represented +--- @field hours number? Amount of hours represented +--- @field minutes number? Amount of minutes represented +--- @field seconds number? Amount of seconds represented + +--- Extract different time units from an amount of ticks +--- @param ticks number The number of ticks which will be represented, can be any duration or time value +--- @param units Common.format_time_param_units A table selecting which units should be displayed, options are: days, hours, minutes, seconds +--- @return Common.extract_time_units_return +function ExpUtil.extract_time_units(ticks, units) + -- Calculate the values to be determine the display values + local max_days, max_hours, max_minutes, max_seconds = ticks / 5184000, ticks / 216000, ticks / 3600, ticks / 60 + + local rtn = { + day = floor(max_days), + hours = floor(max_hours - floor(max_days) * 24), + minutes = floor(max_minutes - floor(max_hours) * 60), + seconds = floor(max_seconds - floor(max_minutes) * 60), + } + + -- Remove units that are not requested + if not units.days then + rtn.hours = rtn.hours + rtn.days * 24 + rtn.days = nil + end + if not units.hours then + rtn.minutes = rtn.minutes + rtn.hours * 60 + rtn.hours = nil + end + if not units.minutes then + rtn.seconds = rtn.seconds + rtn.minutes * 60 + rtn.minutes = nil + end + if not units.seconds then + rtn.seconds = nil + end + + return rtn +end + --- Format a tick value into one of a selection of pre-defined formats (short, long, clock) --- @param ticks number|nil The number of ticks which will be represented, can be any duration or time value --- @param format Common.format_time_param_format format to display, must be one of: short, long, clock --- @param units Common.format_time_param_units A table selecting which units should be displayed, options are: days, hours, minutes, seconds --- @return string # The ticks formatted into a string of the desired format function ExpUtil.format_time(ticks, format, units) - --- @type string | number, string | number, string | number, string | number - local rtn_days, rtn_hours, rtn_minutes, rtn_seconds = "--", "--", "--", "--" - - if ticks ~= nil then - -- Calculate the values to be determine the display values - local max_days, max_hours, max_minutes, max_seconds = ticks / 5184000, ticks / 216000, ticks / 3600, ticks / 60 - local days, hours = max_days, max_hours - floor(max_days) * 24 - local minutes, seconds = max_minutes - floor(max_hours) * 60, max_seconds - floor(max_minutes) * 60 - - -- Calculate rhw units to be displayed - rtn_days, rtn_hours, rtn_minutes, rtn_seconds = floor(days), floor(hours), floor(minutes), floor(seconds) - if not units.days then rtn_hours = rtn_hours + rtn_days * 24 end - if not units.hours then rtn_minutes = rtn_minutes + rtn_hours * 60 end - if not units.minutes then rtn_seconds = rtn_seconds + rtn_minutes * 60 end - end + local times = ticks and ExpUtil.extract_time_units(ticks, units) or {} local rtn = {} if format == "clock" then - if ticks then - -- When ticks is not nil, all rtn values are numbers - local f = "%02d" - rtn_days, rtn_hours = f:format(rtn_days), f:format(rtn_hours) - rtn_minutes, rtn_seconds = f:format(rtn_minutes), f:format(rtn_seconds) - end - -- Example 12:34:56 or --:--:-- - if units.days then rtn[#rtn + 1] = rtn_days end - if units.hours then rtn[#rtn + 1] = rtn_hours end - if units.minutes then rtn[#rtn + 1] = rtn_minutes end - if units.seconds then rtn[#rtn + 1] = rtn_seconds end + -- Example '12:34:56' or '--:--:--' + local f = "%02d" + if units.days then rtn[#rtn + 1] = ticks and f:format(times.days) or "--" end + if units.hours then rtn[#rtn + 1] = ticks and f:format(times.hours) or "--" end + if units.minutes then rtn[#rtn + 1] = ticks and f:format(times.minutes) or "--" end + if units.seconds then rtn[#rtn + 1] = ticks and f:format(times.seconds) or "--" end return concat(rtn, ":") elseif format == "short" then - -- Example 12d 34h 56m or --d --h --m - if units.days then rtn[#rtn + 1] = rtn_days .. "d" end - if units.hours then rtn[#rtn + 1] = rtn_hours .. "h" end - if units.minutes then rtn[#rtn + 1] = rtn_minutes .. "m" end - if units.seconds then rtn[#rtn + 1] = rtn_seconds .. "s" end + -- Example '12d 34h 56m' or '--d --h --m' + if units.days then rtn[#rtn + 1] = (times.days or "--") .. "d" end + if units.hours then rtn[#rtn + 1] = (times.hours or "--") .. "h" end + if units.minutes then rtn[#rtn + 1] = (times.minutes or "--") .. "m" end + if units.seconds then rtn[#rtn + 1] = (times.seconds or "--") .. "s" end return concat(rtn, " ") else - -- Example 12 days, 34 hours, and 56 minutes or -- days, -- hours, and -- minutes - if units.days then rtn[#rtn + 1] = rtn_days .. " days" end - if units.hours then rtn[#rtn + 1] = rtn_hours .. " hours" end - if units.minutes then rtn[#rtn + 1] = rtn_minutes .. " minutes" end - if units.seconds then rtn[#rtn + 1] = rtn_seconds .. " seconds" end + -- Example '12 days, 34 hours, and 56 minutes' or 'nan days, nan hours, and nan minutes' + local nan = 0 / 0 + if units.days then rtn[#rtn + 1] = (times.days or nan) .. " days" end + if units.hours then rtn[#rtn + 1] = (times.hours or nan) .. " hours" end + if units.minutes then rtn[#rtn + 1] = (times.minutes or nan) .. " minutes" end + if units.seconds then rtn[#rtn + 1] = (times.seconds or nan) .. " seconds" end if #rtn > 1 then rtn[#rtn] = "and " .. rtn[#rtn] end @@ -318,50 +339,32 @@ end --- @param units Common.format_time_param_units A table selecting which units should be displayed, options are: days, hours, minutes, seconds --- @return LocalisedString # The ticks formatted into a string of the desired format function ExpUtil.format_time_locale(ticks, format, units) - --- @type string | number, string | number, string | number, string | number - local rtn_days, rtn_hours, rtn_minutes, rtn_seconds = "--", "--", "--", "--" - - if ticks ~= nil then - -- Calculate the values to be determine the display values - local max_days, max_hours, max_minutes, max_seconds = ticks / 5184000, ticks / 216000, ticks / 3600, ticks / 60 - local days, hours = max_days, max_hours - floor(max_days) * 24 - local minutes, seconds = max_minutes - floor(max_hours) * 60, max_seconds - floor(max_minutes) * 60 - - -- Calculate rhw units to be displayed - rtn_days, rtn_hours, rtn_minutes, rtn_seconds = floor(days), floor(hours), floor(minutes), floor(seconds) - if not units.days then rtn_hours = rtn_hours + rtn_days * 24 end - if not units.hours then rtn_minutes = rtn_minutes + rtn_hours * 60 end - if not units.minutes then rtn_seconds = rtn_seconds + rtn_minutes * 60 end - end + local times = ticks and ExpUtil.extract_time_units(ticks, units) or {} local rtn = {} local join = ", " --- @type LocalisedString if format == "clock" then - -- Example 12:34:56 or --:--:-- - if ticks then - -- When ticks is not nil, all rtn values are numbers - local f = "%02d" - rtn_days, rtn_hours = f:format(rtn_days), f:format(rtn_hours) - rtn_minutes, rtn_seconds = f:format(rtn_minutes), f:format(rtn_seconds) - end - if units.days then rtn[#rtn + 1] = rtn_days end - if units.hours then rtn[#rtn + 1] = rtn_hours end - if units.minutes then rtn[#rtn + 1] = rtn_minutes end - if units.seconds then rtn[#rtn + 1] = rtn_seconds end + -- Example '12:34:56' or '--:--:--' + local f = "%02d" + if units.days then rtn[#rtn + 1] = ticks and f:format(times.days) or "--" end + if units.hours then rtn[#rtn + 1] = ticks and f:format(times.hours) or "--" end + if units.minutes then rtn[#rtn + 1] = ticks and f:format(times.minutes) or "--" end + if units.seconds then rtn[#rtn + 1] = ticks and f:format(times.seconds) or "--" end join = { "colon" } elseif format == "short" then - -- Example 12d 34h 56m or --d --h --m - if units.days then rtn[#rtn + 1] = { "?", { "time-symbol-days-short", rtn_days }, rtn_days .. "d" } end - if units.hours then rtn[#rtn + 1] = { "time-symbol-hours-short", rtn_hours } end - if units.minutes then rtn[#rtn + 1] = { "time-symbol-minutes-short", rtn_minutes } end - if units.seconds then rtn[#rtn + 1] = { "time-symbol-seconds-short", rtn_seconds } end + -- Example '12d 34h 56m' or '--d --h --m' + if units.days then rtn[#rtn + 1] = { "?", { "time-symbol-days-short", times.days or "--" }, (times.days or "--") .. "d" } end + if units.hours then rtn[#rtn + 1] = { "time-symbol-hours-short", times.hours or "--" } end + if units.minutes then rtn[#rtn + 1] = { "time-symbol-minutes-short", times.minutes or "--" } end + if units.seconds then rtn[#rtn + 1] = { "time-symbol-seconds-short", times.seconds or "--" } end join = " " else - -- Example 12 days, 34 hours, and 56 minutes or -- days, -- hours, and -- minutes - if units.days then rtn[#rtn + 1] = { "days", rtn_days } end - if units.hours then rtn[#rtn + 1] = { "hours", rtn_hours } end - if units.minutes then rtn[#rtn + 1] = { "minutes", rtn_minutes } end - if units.seconds then rtn[#rtn + 1] = { "seconds", rtn_seconds } end + -- Example '12 days, 34 hours, and 56 minutes' or 'nan days, nan hours, and nan minutes' + local nan = 0 / 0 + if units.days then rtn[#rtn + 1] = { "days", times.days or nan } end + if units.hours then rtn[#rtn + 1] = { "hours", times.hours or nan } end + if units.minutes then rtn[#rtn + 1] = { "minutes", times.minutes or nan } end + if units.seconds then rtn[#rtn + 1] = { "seconds", times.seconds or nan } end if #rtn > 1 then rtn[#rtn] = { "", { "and" }, " ", rtn[#rtn] } end