mirror of
https://github.com/koreader/koreader.git
synced 2025-12-24 12:14:05 +01:00
Duration format: Add spaces, remove lead zeros for Letters (#10141)
* Add thinspaces between d/h/m/s * Remove lead zeros * Make letter `d` for days translatable * Make thinspace into hairspace when compact * Adjust and add unit tests
This commit is contained in:
@@ -100,10 +100,10 @@ function datetime.secondsToClock(seconds, withoutSeconds, withDays)
|
|||||||
mins = string.format("%02d", 0)
|
mins = string.format("%02d", 0)
|
||||||
hours = string.format("%02d", hours + 1)
|
hours = string.format("%02d", hours + 1)
|
||||||
end
|
end
|
||||||
return (days ~= "0" and (days .. "d") or "") .. hours .. ":" .. mins
|
return (days ~= "0" and (days .. C_("Time", "d")) or "") .. hours .. ":" .. mins
|
||||||
else
|
else
|
||||||
local secs = string.format("%02d", seconds % 60)
|
local secs = string.format("%02d", seconds % 60)
|
||||||
return (days ~= "0" and (days .. "d") or "") .. hours .. ":" .. mins .. ":" .. secs
|
return (days ~= "0" and (days .. C_("Time", "d")) or "") .. hours .. ":" .. mins .. ":" .. secs
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -111,10 +111,10 @@ end
|
|||||||
--- Converts seconds to a period of time string.
|
--- Converts seconds to a period of time string.
|
||||||
---- @int seconds number of seconds
|
---- @int seconds number of seconds
|
||||||
---- @bool withoutSeconds if true 1h30', if false 1h30'10"
|
---- @bool withoutSeconds if true 1h30', if false 1h30'10"
|
||||||
---- @bool hmsFormat, if true format 1h30m10s
|
---- @bool hmsFormat, if true format 1h 30m 10s
|
||||||
---- @bool withDays, if true format 1d12h30m10s
|
---- @bool withDays, if true format 1d12h30'10" or 1d 12h 30m 10s
|
||||||
---- @bool compact, if set removes all leading zeros (incl. units if necessary)
|
---- @bool compact, if set removes all leading zeros (incl. units if necessary) and turns thinspaces into hairspaces (if present)
|
||||||
---- @treturn string clock string in the form of 1h30'10" or 1h30m10s
|
---- @treturn string clock string in the form of 1h30'10" or 1h 30m 10s
|
||||||
function datetime.secondsToHClock(seconds, withoutSeconds, hmsFormat, withDays, compact)
|
function datetime.secondsToHClock(seconds, withoutSeconds, hmsFormat, withDays, compact)
|
||||||
local SECONDS_SYMBOL = "\""
|
local SECONDS_SYMBOL = "\""
|
||||||
seconds = tonumber(seconds)
|
seconds = tonumber(seconds)
|
||||||
@@ -150,7 +150,7 @@ function datetime.secondsToHClock(seconds, withoutSeconds, hmsFormat, withDays,
|
|||||||
if compact then
|
if compact then
|
||||||
return T(C_("Time", "%1s"), string.format("%d", seconds))
|
return T(C_("Time", "%1s"), string.format("%d", seconds))
|
||||||
else
|
else
|
||||||
return T(C_("Time", "%1m%2s"), "0", string.format("%02d", seconds))
|
return T(C_("Time", "%1m\xE2\x80\x89%2s"), "0", string.format("%d", seconds))
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
if compact then
|
if compact then
|
||||||
@@ -177,7 +177,16 @@ function datetime.secondsToHClock(seconds, withoutSeconds, hmsFormat, withDays,
|
|||||||
end
|
end
|
||||||
|
|
||||||
if hmsFormat then
|
if hmsFormat then
|
||||||
return withoutSeconds and time_string or (time_string .. C_("Time", "s"))
|
time_string = time_string:gsub("0(%d)", "%1") -- delete all leading "0"s
|
||||||
|
time_string = time_string:gsub(C_("Time", "d"), C_("Time", "d") .. "\xE2\x80\x89") -- add thin space after "d"
|
||||||
|
time_string = time_string:gsub(C_("Time", "h"), C_("Time", "h") .. "\xE2\x80\x89") -- add thin space after "h"
|
||||||
|
if not withoutSeconds then
|
||||||
|
time_string = time_string:gsub(C_("Time", "m"), C_("Time", "m") .. "\xE2\x80\x89") .. C_("Time", "s") -- add thin space after "m"
|
||||||
|
end
|
||||||
|
if compact then
|
||||||
|
time_string = time_string:gsub("\xE2\x80\x89", "\xE2\x80\x8A") -- replace thin space with hair space
|
||||||
|
end
|
||||||
|
return time_string
|
||||||
else
|
else
|
||||||
time_string = time_string:gsub(C_("Time", "m"), "'") -- replace m with '
|
time_string = time_string:gsub(C_("Time", "m"), "'") -- replace m with '
|
||||||
return withoutSeconds and time_string or (time_string .. SECONDS_SYMBOL)
|
return withoutSeconds and time_string or (time_string .. SECONDS_SYMBOL)
|
||||||
@@ -187,11 +196,11 @@ end
|
|||||||
|
|
||||||
--- Converts seconds to a clock type (classic or modern), based on the given format preference
|
--- Converts seconds to a clock type (classic or modern), based on the given format preference
|
||||||
--- "Classic" format calls secondsToClock, "Modern" and "Letters" formats call secondsToHClock
|
--- "Classic" format calls secondsToClock, "Modern" and "Letters" formats call secondsToHClock
|
||||||
---- @string Either "modern" for 1h30'10", "letters" for 1h30m10s, or "classic" for 1:30:10
|
---- @string Either "modern" for 1h30'10", "letters" for 1h 30m 10s, or "classic" for 1:30:10
|
||||||
---- @bool withoutSeconds if true 1h30' or 1h30m, if false 1h30'10" or 1h30m10s
|
---- @bool withoutSeconds if true 1h30' or 1h 30m, if false 1h30'10" or 1h 30m 10s
|
||||||
---- @bool withDays, if hours>=24 include days in clock string 1d12h10m10s
|
---- @bool withDays, if hours>=24 include days in clock string 1d12h10'10" or 1d 12h 10m 10s
|
||||||
---- @bool compact, if set removes all leading zeros (incl. units if necessary)
|
---- @bool compact, if set removes all leading zeros (incl. units if necessary) and turns thinspaces into hairspaces (if present)
|
||||||
---- @treturn string clock string in the specific format of 1h30', 1h30'10" resp. 1h30m, 1h30m10s
|
---- @treturn string clock string in the specific format of 1h30', 1h30'10" resp. 1h 30m, 1h 30m 10s
|
||||||
function datetime.secondsToClockDuration(format, seconds, withoutSeconds, withDays, compact)
|
function datetime.secondsToClockDuration(format, seconds, withoutSeconds, withDays, compact)
|
||||||
if format == "modern" then
|
if format == "modern" then
|
||||||
return datetime.secondsToHClock(seconds, withoutSeconds, false, withDays, compact)
|
return datetime.secondsToHClock(seconds, withoutSeconds, false, withDays, compact)
|
||||||
|
|||||||
@@ -128,7 +128,7 @@ common_settings.time = {
|
|||||||
{
|
{
|
||||||
text_func = function()
|
text_func = function()
|
||||||
local datetime = require("datetime")
|
local datetime = require("datetime")
|
||||||
-- sample text shows 1h23m45s
|
-- sample text shows 1h 23m 45s
|
||||||
local duration_format_str = datetime.secondsToClockDuration("letters", 5025, false)
|
local duration_format_str = datetime.secondsToClockDuration("letters", 5025, false)
|
||||||
return T(C_("Time", "Letters (%1)"), duration_format_str)
|
return T(C_("Time", "Letters (%1)"), duration_format_str)
|
||||||
end,
|
end,
|
||||||
|
|||||||
@@ -44,10 +44,28 @@ describe("datetime module", function()
|
|||||||
assert.is_equal("00:02:00",
|
assert.is_equal("00:02:00",
|
||||||
datetime.secondsToClock(120))
|
datetime.secondsToClock(120))
|
||||||
end)
|
end)
|
||||||
|
it("should convert seconds to 0d00:00:00 format", function()
|
||||||
|
assert.is_equal("00:00:00",
|
||||||
|
datetime.secondsToClock(0, false, true))
|
||||||
|
assert.is_equal("00:02:00",
|
||||||
|
datetime.secondsToClock(120, false, true))
|
||||||
|
assert.is_equal("5d00:02:00",
|
||||||
|
datetime.secondsToClock(432120, false, true))
|
||||||
|
end)
|
||||||
|
it("should convert seconds to 0d00:00 format", function()
|
||||||
|
assert.is_equal("00:00",
|
||||||
|
datetime.secondsToClock(0, true, true))
|
||||||
|
assert.is_equal("00:02",
|
||||||
|
datetime.secondsToClock(120, true, true))
|
||||||
|
assert.is_equal("5d00:02",
|
||||||
|
datetime.secondsToClock(432110, true, true))
|
||||||
|
assert.is_equal("5d00:02",
|
||||||
|
datetime.secondsToClock(432120, true, true))
|
||||||
|
end)
|
||||||
end)
|
end)
|
||||||
|
|
||||||
describe("secondsToHClock()", function()
|
describe("secondsToHClock()", function()
|
||||||
it("should convert seconds to 0'00'' format", function()
|
it("should convert seconds to 0' format", function()
|
||||||
assert.is_equal("0'",
|
assert.is_equal("0'",
|
||||||
datetime.secondsToHClock(0, true))
|
datetime.secondsToHClock(0, true))
|
||||||
assert.is_equal("0'",
|
assert.is_equal("0'",
|
||||||
@@ -75,22 +93,38 @@ describe("datetime module", function()
|
|||||||
assert.is_equal("10h01'",
|
assert.is_equal("10h01'",
|
||||||
datetime.secondsToHClock(36060, true))
|
datetime.secondsToHClock(36060, true))
|
||||||
end)
|
end)
|
||||||
it("should round seconds to minutes in 0h00m format", function()
|
it("should round seconds to minutes in 0h 0m (thinspace) format", function()
|
||||||
assert.is_equal("1m",
|
assert.is_equal("1m",
|
||||||
datetime.secondsToHClock(89, true, true))
|
datetime.secondsToHClock(89, true, true))
|
||||||
assert.is_equal("2m",
|
assert.is_equal("2m",
|
||||||
datetime.secondsToHClock(90, true, true))
|
datetime.secondsToHClock(90, true, true))
|
||||||
assert.is_equal("2m",
|
assert.is_equal("2m",
|
||||||
datetime.secondsToHClock(110, true, true))
|
datetime.secondsToHClock(110, true, true))
|
||||||
assert.is_equal("1h00m",
|
assert.is_equal("1h\xE2\x80\x890m",
|
||||||
datetime.secondsToHClock(3600, true, true))
|
datetime.secondsToHClock(3600, true, true))
|
||||||
assert.is_equal("1h00m",
|
assert.is_equal("1h\xE2\x80\x890m",
|
||||||
datetime.secondsToHClock(3599, true, true))
|
datetime.secondsToHClock(3599, true, true))
|
||||||
assert.is_equal("59m",
|
assert.is_equal("59m",
|
||||||
datetime.secondsToHClock(3569, true, true))
|
datetime.secondsToHClock(3569, true, true))
|
||||||
assert.is_equal("10h01m",
|
assert.is_equal("10h\xE2\x80\x891m",
|
||||||
datetime.secondsToHClock(36060, true, true))
|
datetime.secondsToHClock(36060, true, true))
|
||||||
end)
|
end)
|
||||||
|
it("should round seconds to minutes in 0h 0m (hairspace) format", function()
|
||||||
|
assert.is_equal("1m",
|
||||||
|
datetime.secondsToHClock(89, true, true, false, true))
|
||||||
|
assert.is_equal("2m",
|
||||||
|
datetime.secondsToHClock(90, true, true, false, true))
|
||||||
|
assert.is_equal("2m",
|
||||||
|
datetime.secondsToHClock(110, true, true, false, true))
|
||||||
|
assert.is_equal("1h\xE2\x80\x8A0m",
|
||||||
|
datetime.secondsToHClock(3600, true, true, false, true))
|
||||||
|
assert.is_equal("1h\xE2\x80\x8A0m",
|
||||||
|
datetime.secondsToHClock(3599, true, true, false, true))
|
||||||
|
assert.is_equal("59m",
|
||||||
|
datetime.secondsToHClock(3569, true, true, false, true))
|
||||||
|
assert.is_equal("10h\xE2\x80\x8A1m",
|
||||||
|
datetime.secondsToHClock(36060, true, true, false, true))
|
||||||
|
end)
|
||||||
it("should convert seconds to 0h00'00'' format", function()
|
it("should convert seconds to 0h00'00'' format", function()
|
||||||
assert.is_equal("0\"",
|
assert.is_equal("0\"",
|
||||||
datetime.secondsToHClock(0))
|
datetime.secondsToHClock(0))
|
||||||
@@ -111,7 +145,7 @@ describe("datetime module", function()
|
|||||||
it("should change type based on format", function()
|
it("should change type based on format", function()
|
||||||
assert.is_equal("10h01'30\"",
|
assert.is_equal("10h01'30\"",
|
||||||
datetime.secondsToClockDuration("modern", 36090, false))
|
datetime.secondsToClockDuration("modern", 36090, false))
|
||||||
assert.is_equal("10h01m30s",
|
assert.is_equal("10h\xE2\x80\x891m\xE2\x80\x8930s",
|
||||||
datetime.secondsToClockDuration("letters", 36090, false))
|
datetime.secondsToClockDuration("letters", 36090, false))
|
||||||
assert.is_equal("10:01:30",
|
assert.is_equal("10:01:30",
|
||||||
datetime.secondsToClockDuration("classic", 36090, false))
|
datetime.secondsToClockDuration("classic", 36090, false))
|
||||||
@@ -125,15 +159,29 @@ describe("datetime module", function()
|
|||||||
datetime.secondsToClockDuration("modern", 36090, false))
|
datetime.secondsToClockDuration("modern", 36090, false))
|
||||||
assert.is_equal("10h02'",
|
assert.is_equal("10h02'",
|
||||||
datetime.secondsToClockDuration("modern", 36090, true))
|
datetime.secondsToClockDuration("modern", 36090, true))
|
||||||
assert.is_equal("10h01m30s",
|
assert.is_equal("10h\xE2\x80\x891m\xE2\x80\x8930s",
|
||||||
datetime.secondsToClockDuration("letters", 36090, false))
|
datetime.secondsToClockDuration("letters", 36090, false))
|
||||||
assert.is_equal("10h02m",
|
assert.is_equal("10h\xE2\x80\x892m",
|
||||||
datetime.secondsToClockDuration("letters", 36090, true))
|
datetime.secondsToClockDuration("letters", 36090, true))
|
||||||
assert.is_equal("10:01:30",
|
assert.is_equal("10:01:30",
|
||||||
datetime.secondsToClockDuration("classic", 36090, false))
|
datetime.secondsToClockDuration("classic", 36090, false))
|
||||||
assert.is_equal("10:02",
|
assert.is_equal("10:02",
|
||||||
datetime.secondsToClockDuration("classic", 36090, true))
|
datetime.secondsToClockDuration("classic", 36090, true))
|
||||||
end)
|
end)
|
||||||
|
it("should pass along withDays", function()
|
||||||
|
assert.is_equal("58h01'30\"",
|
||||||
|
datetime.secondsToClockDuration("modern", 208890, false, false))
|
||||||
|
assert.is_equal("2d10h01'30\"",
|
||||||
|
datetime.secondsToClockDuration("modern", 208890, false, true))
|
||||||
|
assert.is_equal("58h\xE2\x80\x891m\xE2\x80\x8930s",
|
||||||
|
datetime.secondsToClockDuration("letters", 208890, false, false))
|
||||||
|
assert.is_equal("2d\xE2\x80\x8910h\xE2\x80\x891m\xE2\x80\x8930s",
|
||||||
|
datetime.secondsToClockDuration("letters", 208890, false, true))
|
||||||
|
assert.is_equal("58:01:30",
|
||||||
|
datetime.secondsToClockDuration("classic", 208890, false, false))
|
||||||
|
assert.is_equal("2d10:01:30",
|
||||||
|
datetime.secondsToClockDuration("classic", 208890, false, true))
|
||||||
|
end)
|
||||||
end)
|
end)
|
||||||
|
|
||||||
describe("secondsToDate()", function()
|
describe("secondsToDate()", function()
|
||||||
|
|||||||
Reference in New Issue
Block a user