diff --git a/frontend/apps/reader/modules/readerfooter.lua b/frontend/apps/reader/modules/readerfooter.lua
index 6355189c0..edbc1869d 100644
--- a/frontend/apps/reader/modules/readerfooter.lua
+++ b/frontend/apps/reader/modules/readerfooter.lua
@@ -20,8 +20,8 @@ local UIManager = require("ui/uimanager")
local VerticalGroup = require("ui/widget/verticalgroup")
local VerticalSpan = require("ui/widget/verticalspan")
local WidgetContainer = require("ui/widget/container/widgetcontainer")
+local datetime = require("datetime")
local logger = require("logger")
-local util = require("util")
local T = require("ffi/util").template
local _ = require("gettext")
local C_ = _.pgettext
@@ -229,7 +229,7 @@ local footerTextGeneratorMap = {
time = function(footer)
local symbol_type = footer.settings.item_prefix
local prefix = symbol_prefix[symbol_type].time
- local clock = util.secondsToHour(os.time(), G_reader_settings:isTrue("twelve_hour_clock"))
+ local clock = datetime.secondsToHour(os.time(), G_reader_settings:isTrue("twelve_hour_clock"))
if not prefix then
return clock
else
@@ -2098,7 +2098,7 @@ function ReaderFooter:getDataFromStatistics(title, pages)
local average_time_per_page = self:getAvgTimePerPage()
local user_duration_format = G_reader_settings:readSetting("duration_format", "classic")
if average_time_per_page then
- sec = util.secondsToClockDuration(user_duration_format, pages * average_time_per_page, true)
+ sec = datetime.secondsToClockDuration(user_duration_format, pages * average_time_per_page, true)
end
return title .. sec
end
diff --git a/frontend/datetime.lua b/frontend/datetime.lua
new file mode 100644
index 000000000..26317c3b2
--- /dev/null
+++ b/frontend/datetime.lua
@@ -0,0 +1,296 @@
+--[[--
+This module contains date translations and helper functions for the KOReader frontend.
+]]
+
+local BaseUtil = require("ffi/util")
+local _ = require("gettext")
+local C_ = _.pgettext
+local T = BaseUtil.template
+
+local datetime = {}
+
+datetime.weekDays = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" } -- in Lua wday order
+
+datetime.shortMonthTranslation = {
+ ["Jan"] = _("Jan"),
+ ["Feb"] = _("Feb"),
+ ["Mar"] = _("Mar"),
+ ["Apr"] = _("Apr"),
+ ["May"] = _("May"),
+ ["Jun"] = _("Jun"),
+ ["Jul"] = _("Jul"),
+ ["Aug"] = _("Aug"),
+ ["Sep"] = _("Sep"),
+ ["Oct"] = _("Oct"),
+ ["Nov"] = _("Nov"),
+ ["Dec"] = _("Dec"),
+}
+
+datetime.longMonthTranslation = {
+ ["January"] = _("January"),
+ ["February"] = _("February"),
+ ["March"] = _("March"),
+ ["April"] = _("April"),
+ ["May"] = _("May"),
+ ["June"] = _("June"),
+ ["July"] = _("July"),
+ ["August"] = _("August"),
+ ["September"] = _("September"),
+ ["October"] = _("October"),
+ ["November"] = _("November"),
+ ["December"] = _("December"),
+}
+
+datetime.shortDayOfWeekTranslation = {
+ ["Mon"] = _("Mon"),
+ ["Tue"] = _("Tue"),
+ ["Wed"] = _("Wed"),
+ ["Thu"] = _("Thu"),
+ ["Fri"] = _("Fri"),
+ ["Sat"] = _("Sat"),
+ ["Sun"] = _("Sun"),
+}
+
+datetime.shortDayOfWeekToLongTranslation = {
+ ["Mon"] = _("Monday"),
+ ["Tue"] = _("Tuesday"),
+ ["Wed"] = _("Wednesday"),
+ ["Thu"] = _("Thursday"),
+ ["Fri"] = _("Friday"),
+ ["Sat"] = _("Saturday"),
+ ["Sun"] = _("Sunday"),
+}
+
+--[[--
+Converts seconds to a clock string.
+
+Source: https://gist.github.com/jesseadams/791673
+]]
+---- @int seconds number of seconds
+---- @bool withoutSeconds if true 00:00, if false 00:00:00
+---- @treturn string clock string in the form of 00:00 or 00:00:00
+function datetime.secondsToClock(seconds, withoutSeconds, withDays)
+ seconds = tonumber(seconds)
+ if not seconds then
+ if withoutSeconds then
+ return "--:--"
+ else
+ return "--:--:--"
+ end
+ elseif seconds == 0 or seconds ~= seconds then
+ if withoutSeconds then
+ return "00:00"
+ else
+ return "00:00:00"
+ end
+ else
+ local round = withoutSeconds and require("optmath").round or function(n) return n end
+ local days = "0"
+ local hours
+ if withDays then
+ days = string.format("%d", seconds * (1/(24*3600))) -- implicit math.floor for string.format
+ hours = string.format("%02d", (seconds * (1/3600)) % 24)
+ else
+ hours = string.format("%02d", seconds * (1/3600))
+ end
+ local mins = string.format("%02d", round(seconds % 3600 * (1/60)))
+ if withoutSeconds then
+ if mins == "60" then
+ -- Can only happen because of rounding, which only happens if withoutSeconds...
+ mins = string.format("%02d", 0)
+ hours = string.format("%02d", hours + 1)
+ end
+ return (days ~= "0" and (days .. "d") or "") .. hours .. ":" .. mins
+ else
+ local secs = string.format("%02d", seconds % 60)
+ return (days ~= "0" and (days .. "d") or "") .. hours .. ":" .. mins .. ":" .. secs
+ end
+ end
+end
+
+--- Converts seconds to a period of time string.
+---- @int seconds number of seconds
+---- @bool withoutSeconds if true 1h30', if false 1h30'10"
+---- @bool hmsFormat, if true format 1h30m10s
+---- @bool withDays, if true format 1d12h30m10s
+---- @treturn string clock string in the form of 1h30'10" or 1h30m10s
+function datetime.secondsToHClock(seconds, withoutSeconds, hmsFormat, withDays, compact)
+ local SECONDS_SYMBOL = "\""
+ seconds = tonumber(seconds)
+ if seconds == 0 then
+ if withoutSeconds then
+ if hmsFormat then
+ return T(_("%1m"), "0")
+ else
+ return "0'"
+ end
+ else
+ if hmsFormat then
+ return T(C_("Time", "%1s"), "0")
+ else
+ return "0" .. SECONDS_SYMBOL
+ end
+ end
+ elseif seconds < 60 then
+ if withoutSeconds and seconds < 30 then
+ if hmsFormat then
+ return T(C_("Time", "%1m"), "0")
+ else
+ return "0'"
+ end
+ elseif withoutSeconds and seconds >= 30 then
+ if hmsFormat then
+ return T(C_("Time", "%1m"), "1")
+ else
+ return "1'"
+ end
+ else
+ if hmsFormat then
+ if compact then
+ return T(C_("Time", "%1s"), string.format("%d", seconds))
+ else
+ return T(C_("Time", "%1m%2s"), "0", string.format("%02d", seconds))
+ end
+ else
+ if compact then
+ return string.format("%d", seconds) .. SECONDS_SYMBOL
+ else
+ return "0'" .. string.format("%02d", seconds) .. SECONDS_SYMBOL
+ end
+ end
+ end
+ else
+ local time_string = datetime.secondsToClock(seconds, withoutSeconds, withDays)
+ if withoutSeconds then
+ time_string = time_string .. ":"
+ end
+ time_string = time_string:gsub(":", C_("Time", "h"), 1)
+ time_string = time_string:gsub(":", C_("Time", "m"), 1)
+ time_string = time_string:gsub("^00" .. C_("Time", "h"), "") -- delete leading "00h"
+ time_string = time_string:gsub("^00" .. C_("Time", "m"), "") -- delete leading "00m"
+ if time_string:find("^0%d") then
+ time_string = time_string:gsub("^0", "") -- delete leading "0"
+ end
+ if withoutSeconds and time_string == "" then
+ time_string = "0" .. C_("Time", "m")
+ end
+
+ if hmsFormat then
+ return withoutSeconds and time_string or (time_string .. C_("Time", "s"))
+ else
+ time_string = time_string:gsub(C_("Time", "m"), "'") -- replace m with '
+ return withoutSeconds and time_string or (time_string .. SECONDS_SYMBOL)
+ end
+ end
+end
+
+--- Converts seconds to a clock type (classic or modern), based on the given format preference
+--- "Classic" format calls secondsToClock, and "Modern" format calls secondsToHClock
+---- @string Either "modern" for 1h30'10" or "classic" for 1:30:10
+---- @bool withoutSeconds if true 1h30' or 1h30m, if false 1h30'10" or 1h30m10s
+---- @bool hmsFormat, modern format only, if true format 1h30m or 1h30m10s
+---- @bool withDays, if hours>=24 include days in clock string 1d12h10m10s
+---- @bool compact, if set removes all leading zeros (incl. units if necessary)
+---- @treturn string clock string in the specific format of 1h30', 1h30'10" resp. 1h30m, 1h30m10s
+function datetime.secondsToClockDuration(format, seconds, withoutSeconds, hmsFormat, withDays, compact)
+ if format == "modern" then
+ return datetime.secondsToHClock(seconds, withoutSeconds, hmsFormat, withDays, compact)
+ else
+ -- Assume "classic" to give safe default
+ return datetime.secondsToClock(seconds, withoutSeconds, withDays)
+ end
+end
+
+if jit.os == "Windows" then
+ --- Converts timestamp to an hour string
+ ---- @int seconds number of seconds
+ ---- @bool twelve_hour_clock
+ ---- @treturn string hour string
+ ---- @note: The MS CRT doesn't support either %l & %k, or the - format modifier (as they're not technically C99 or POSIX).
+ ---- They are otherwise supported on Linux, BSD & Bionic, so, just special-case Windows...
+ ---- We *could* arguably feed the os.date output to gsub("^0(%d)(.*)$", "%1%2"), but, while unlikely,
+ ---- it's conceivable that a translator would put something other that the hour at the front of the string ;).
+ function datetime.secondsToHour(seconds, twelve_hour_clock)
+ if twelve_hour_clock then
+ if os.date("%p", seconds) == "AM" then
+ -- @translators This is the time in the morning using a 12-hour clock (%I is the hour, %M the minute).
+ return os.date(_("%I:%M AM"), seconds)
+ else
+ -- @translators This is the time in the afternoon using a 12-hour clock (%I is the hour, %M the minute).
+ return os.date(_("%I:%M PM"), seconds)
+ end
+ else
+ -- @translators This is the time using a 24-hour clock (%H is the hour, %M the minute).
+ return os.date(_("%H:%M"), seconds)
+ end
+ end
+else
+ function datetime.secondsToHour(seconds, twelve_hour_clock, pad_with_spaces)
+ if twelve_hour_clock then
+ if os.date("%p", seconds) == "AM" then
+ if pad_with_spaces then
+ -- @translators This is the time in the morning using a 12-hour clock (%_I is the hour, %M the minute).
+ return os.date(_("%_I:%M AM"), seconds)
+ else
+ -- @translators This is the time in the morning using a 12-hour clock (%-I is the hour, %M the minute).
+ return os.date(_("%-I:%M AM"), seconds)
+ end
+ else
+ if pad_with_spaces then
+ -- @translators This is the time in the afternoon using a 12-hour clock (%_I is the hour, %M the minute).
+ return os.date(_("%_I:%M PM"), seconds)
+ else
+ -- @translators This is the time in the afternoon using a 12-hour clock (%-I is the hour, %M the minute).
+ return os.date(_("%-I:%M PM"), seconds)
+ end
+ end
+ else
+ if pad_with_spaces then
+ -- @translators This is the time using a 24-hour clock (%_H is the hour, %M the minute).
+ return os.date(_("%_H:%M"), seconds)
+ else
+ -- @translators This is the time using a 24-hour clock (%-H is the hour, %M the minute).
+ return os.date(_("%-H:%M"), seconds)
+ end
+ end
+ end
+end
+
+--- Converts timestamp to a date string
+---- @int seconds number of seconds
+---- @use_locale if true allows to translate the date-time string, if false return "%Y-%m-%d time"
+---- @treturn string date string
+function datetime.secondsToDate(seconds, use_locale)
+ seconds = seconds or os.time()
+ if use_locale then
+ local wday = os.date("%a", seconds)
+ local month = os.date("%b", seconds)
+ local day = os.date("%d", seconds)
+ local year = os.date("%Y", seconds)
+
+ -- @translators Use the following placeholders in the desired order: %1 name of day, %2 name of month, %3 day, %4 year
+ return T(C_("Date string", "%1 %2 %3 %4"),
+ datetime.shortDayOfWeekTranslation[wday], datetime.shortMonthTranslation[month], day, year)
+ else
+ -- @translators This is the date (%Y is the year, %m the month, %d the day)
+ return os.date(C_("Date string", "%Y-%m-%d"), seconds)
+ end
+end
+
+--- Converts timestamp to a date+time string
+---- @int seconds number of seconds
+---- @bool twelve_hour_clock
+---- @use_locale if true allows to translate the date-time string, if false return "%Y-%m-%d time"
+---- @treturn string date+time
+function datetime.secondsToDateTime(seconds, twelve_hour_clock, use_locale)
+ seconds = seconds or os.time()
+ local BD = require("ui/bidi")
+ local date_string = datetime.secondsToDate(seconds, use_locale)
+ local time_string = datetime.secondsToHour(seconds, twelve_hour_clock, not use_locale)
+
+ -- @translators Use the following placeholders in the desired order: %1 date, %2 time
+ local message_text = T(C_("Date string", "%1 %2"), BD.wrap(date_string), BD.wrap(time_string))
+ return message_text
+end
+
+return datetime
diff --git a/frontend/readhistory.lua b/frontend/readhistory.lua
index 26a9d1d8a..2afc7782a 100644
--- a/frontend/readhistory.lua
+++ b/frontend/readhistory.lua
@@ -1,5 +1,6 @@
local DataStorage = require("datastorage")
local DocSettings = require("docsettings")
+local datetime = require("datetime")
local dump = require("dump")
local ffiutil = require("ffi/util")
local util = require("util")
@@ -41,7 +42,7 @@ local function buildEntry(input_time, input_file)
-- we fallback to if no sidecar file)
last_read_ts = DocSettings:getLastSaveTime(file_path) or input_time
end
- return util.secondsToDate(last_read_ts, G_reader_settings:isTrue("twelve_hour_clock"))
+ return datetime.secondsToDateTime(last_read_ts, G_reader_settings:isTrue("twelve_hour_clock"))
end,
select_enabled_func = function()
return lfs.attributes(file_path, "mode") == "file"
diff --git a/frontend/ui/elements/common_settings_menu_table.lua b/frontend/ui/elements/common_settings_menu_table.lua
index d5af2ae43..b89234db2 100644
--- a/frontend/ui/elements/common_settings_menu_table.lua
+++ b/frontend/ui/elements/common_settings_menu_table.lua
@@ -91,9 +91,9 @@ common_settings.time = {
sub_item_table = {
{
text_func = function()
- local util = require('util')
+ local datetime = require("datetime")
-- sample text shows 1:23:45
- local duration_format_str = util.secondsToClockDuration("classic", 5025, false)
+ local duration_format_str = datetime.secondsToClockDuration("classic", 5025, false)
return T(_("Classic (%1)"), duration_format_str)
end,
checked_func = function()
@@ -106,9 +106,9 @@ common_settings.time = {
},
{
text_func = function()
- local util = require('util')
+ local datetime = require("datetime")
-- sample text shows 1h23m45s
- local duration_format_str = util.secondsToClockDuration("modern", 5025, false)
+ local duration_format_str = datetime.secondsToClockDuration("modern", 5025, false)
return T(_("Modern (%1)"), duration_format_str)
end,
checked_func = function()
diff --git a/frontend/ui/screensaver.lua b/frontend/ui/screensaver.lua
index 75800ba61..a23c5bd5c 100644
--- a/frontend/ui/screensaver.lua
+++ b/frontend/ui/screensaver.lua
@@ -19,6 +19,7 @@ local TopContainer = require("ui/widget/container/topcontainer")
local UIManager = require("ui/uimanager")
local VerticalGroup = require("ui/widget/verticalgroup")
local VerticalSpan = require("ui/widget/verticalspan")
+local datetime = require("datetime")
local ffiUtil = require("ffi/util")
local lfs = require("libs/libkoreader-lfs")
local logger = require("logger")
@@ -130,7 +131,7 @@ function Screensaver:_calcAverageTimeForPages(pages)
-- Compare average_time_per_page against itself to make sure it's not nan
if average_time_per_page and average_time_per_page == average_time_per_page and pages then
local user_duration_format = G_reader_settings:readSetting("duration_format", "classic")
- sec = util.secondsToClockDuration(user_duration_format, pages * average_time_per_page, true)
+ sec = datetime.secondsToClockDuration(user_duration_format, pages * average_time_per_page, true)
end
return sec
end
diff --git a/frontend/ui/widget/bookstatuswidget.lua b/frontend/ui/widget/bookstatuswidget.lua
index 9939335f5..402801d03 100644
--- a/frontend/ui/widget/bookstatuswidget.lua
+++ b/frontend/ui/widget/bookstatuswidget.lua
@@ -24,6 +24,7 @@ local ToggleSwitch = require("ui/widget/toggleswitch")
local UIManager = require("ui/uimanager")
local VerticalGroup = require("ui/widget/verticalgroup")
local VerticalSpan = require("ui/widget/verticalspan")
+local datetime = require("datetime")
local util = require("util")
local _ = require("gettext")
local Screen = Device.screen
@@ -144,7 +145,7 @@ end
function BookStatusWidget:getStatHours()
if stats_book.time then
local user_duration_format = G_reader_settings:readSetting("duration_format", "classic")
- return util.secondsToClockDuration(user_duration_format, stats_book.time, false)
+ return datetime.secondsToClockDuration(user_duration_format, stats_book.time, false)
else
return _("N/A")
end
diff --git a/frontend/ui/widget/touchmenu.lua b/frontend/ui/widget/touchmenu.lua
index 81e69edf8..9283d489d 100644
--- a/frontend/ui/widget/touchmenu.lua
+++ b/frontend/ui/widget/touchmenu.lua
@@ -27,7 +27,7 @@ local UIManager = require("ui/uimanager")
local UnderlineContainer = require("ui/widget/container/underlinecontainer")
local VerticalGroup = require("ui/widget/verticalgroup")
local VerticalSpan = require("ui/widget/verticalspan")
-local util = require("util")
+local datetime = require("datetime")
local getMenuText = require("ui/widget/menu").getMenuText
local _ = require("gettext")
local T = require("ffi/util").template
@@ -704,7 +704,7 @@ function TouchMenu:updateItems()
self.page_info_left_chev:enableDisable(self.page > 1)
self.page_info_right_chev:enableDisable(self.page < self.page_num)
- local time_info_txt = util.secondsToHour(os.time(), G_reader_settings:isTrue("twelve_hour_clock"))
+ local time_info_txt = datetime.secondsToHour(os.time(), G_reader_settings:isTrue("twelve_hour_clock"))
local powerd = Device:getPowerDevice()
if Device:hasBattery() then
local batt_lvl = powerd:getCapacity()
diff --git a/frontend/util.lua b/frontend/util.lua
index 65b8d5313..ffaad46a8 100644
--- a/frontend/util.lua
+++ b/frontend/util.lua
@@ -101,219 +101,6 @@ function util.gsplit(str, pattern, capture, capture_empty_entity)
end)
end
--- Stupid helper for the duration stuff
-local function passthrough(n)
- return n
-end
-
---[[--
-Converts seconds to a clock string.
-
-Source: https://gist.github.com/jesseadams/791673
-]]
----- @int seconds number of seconds
----- @bool withoutSeconds if true 00:00, if false 00:00:00
----- @treturn string clock string in the form of 00:00 or 00:00:00
-function util.secondsToClock(seconds, withoutSeconds, withDays)
- seconds = tonumber(seconds)
- if not seconds then
- if withoutSeconds then
- return "--:--"
- else
- return "--:--:--"
- end
- elseif seconds == 0 or seconds ~= seconds then
- if withoutSeconds then
- return "00:00"
- else
- return "00:00:00"
- end
- else
- local round = withoutSeconds and require("optmath").round or passthrough
- local days = "0"
- local hours
- if withDays then
- days = string.format("%d", seconds * (1/(24*3600))) -- implicit math.floor for string.format
- hours = string.format("%02d", (seconds * (1/3600)) % 24)
- else
- hours = string.format("%02d", seconds * (1/3600))
- end
- local mins = string.format("%02d", round(seconds % 3600 * (1/60)))
- if withoutSeconds then
- if mins == "60" then
- -- Can only happen because of rounding, which only happens if withoutSeconds...
- mins = string.format("%02d", 0)
- hours = string.format("%02d", hours + 1)
- end
- return (days ~= "0" and (days .. "d") or "") .. hours .. ":" .. mins
- else
- local secs = string.format("%02d", seconds % 60)
- return (days ~= "0" and (days .. "d") or "") .. hours .. ":" .. mins .. ":" .. secs
- end
- end
-end
-
---- Converts seconds to a period of time string.
----- @int seconds number of seconds
----- @bool withoutSeconds if true 1h30', if false 1h30'10"
----- @bool hmsFormat, if true format 1h30m10s
----- @bool withDays, if true format 1d12h30m10s
----- @treturn string clock string in the form of 1h30'10" or 1h30m10s
-function util.secondsToHClock(seconds, withoutSeconds, hmsFormat, withDays, compact)
- local SECONDS_SYMBOL = "\""
- seconds = tonumber(seconds)
- if seconds == 0 then
- if withoutSeconds then
- if hmsFormat then
- return T(_("%1m"), "0")
- else
- return "0'"
- end
- else
- if hmsFormat then
- return T(C_("Time", "%1s"), "0")
- else
- return "0" .. SECONDS_SYMBOL
- end
- end
- elseif seconds < 60 then
- if withoutSeconds and seconds < 30 then
- if hmsFormat then
- return T(C_("Time", "%1m"), "0")
- else
- return "0'"
- end
- elseif withoutSeconds and seconds >= 30 then
- if hmsFormat then
- return T(C_("Time", "%1m"), "1")
- else
- return "1'"
- end
- else
- if hmsFormat then
- if compact then
- return T(C_("Time", "%1s"), string.format("%d", seconds))
- else
- return T(C_("Time", "%1m%2s"), "0", string.format("%02d", seconds))
- end
- else
- if compact then
- return string.format("%d", seconds) .. SECONDS_SYMBOL
- else
- return "0'" .. string.format("%02d", seconds) .. SECONDS_SYMBOL
- end
- end
- end
- else
- local time_string = util.secondsToClock(seconds, withoutSeconds, withDays)
- if withoutSeconds then
- time_string = time_string .. ":"
- end
- time_string = time_string:gsub(":", C_("Time", "h"), 1)
- time_string = time_string:gsub(":", C_("Time", "m"), 1)
- time_string = time_string:gsub("^00" .. C_("Time", "h"), "") -- delete leading "00h"
- time_string = time_string:gsub("^00" .. C_("Time", "m"), "") -- delete leading "00m"
- if time_string:find("^0%d") then
- time_string = time_string:gsub("^0", "") -- delete leading "0"
- end
- if withoutSeconds and time_string == "" then
- time_string = "0" .. C_("Time", "m")
- end
-
- if hmsFormat then
- return withoutSeconds and time_string or (time_string .. C_("Time", "s"))
- else
- time_string = time_string:gsub(C_("Time", "m"), "'") -- replace m with '
- return withoutSeconds and time_string or (time_string .. SECONDS_SYMBOL)
- end
- end
-end
-
---- Converts seconds to a clock type (classic or modern), based on the given format preference
---- "Classic" format calls secondsToClock, and "Modern" format calls secondsToHClock
----- @string Either "modern" for 1h30'10" or "classic" for 1:30:10
----- @bool withoutSeconds if true 1h30' or 1h30m, if false 1h30'10" or 1h30m10s
----- @bool hmsFormat, modern format only, if true format 1h30m or 1h30m10s
----- @bool withDays, if hours>=24 include days in clock string 1d12h10m10s
----- @bool compact, if set removes all leading zeros (incl. units if necessary)
----- @treturn string clock string in the specific format of 1h30', 1h30'10" resp. 1h30m, 1h30m10s
-function util.secondsToClockDuration(format, seconds, withoutSeconds, hmsFormat, withDays, compact)
- if format == "modern" then
- return util.secondsToHClock(seconds, withoutSeconds, hmsFormat, withDays, compact)
- else
- -- Assume "classic" to give safe default
- return util.secondsToClock(seconds, withoutSeconds, withDays)
- end
-end
-
-if jit.os == "Windows" then
- --- Converts timestamp to an hour string
- ---- @int seconds number of seconds
- ---- @bool twelve_hour_clock
- ---- @treturn string hour string
- ---- @note: The MS CRT doesn't support either %l & %k, or the - format modifier (as they're not technically C99 or POSIX).
- ---- They are otherwise supported on Linux, BSD & Bionic, so, just special-case Windows...
- ---- We *could* arguably feed the os.date output to gsub("^0(%d)(.*)$", "%1%2"), but, while unlikely,
- ---- it's conceivable that a translator would put something other that the hour at the front of the string ;).
- function util.secondsToHour(seconds, twelve_hour_clock)
- if twelve_hour_clock then
- if os.date("%p", seconds) == "AM" then
- -- @translators This is the time in the morning using a 12-hour clock (%I is the hour, %M the minute).
- return os.date(_("%I:%M AM"), seconds)
- else
- -- @translators This is the time in the afternoon using a 12-hour clock (%I is the hour, %M the minute).
- return os.date(_("%I:%M PM"), seconds)
- end
- else
- -- @translators This is the time using a 24-hour clock (%H is the hour, %M the minute).
- return os.date(_("%H:%M"), seconds)
- end
- end
-else
- function util.secondsToHour(seconds, twelve_hour_clock, pad_with_spaces)
- if twelve_hour_clock then
- if os.date("%p", seconds) == "AM" then
- if pad_with_spaces then
- -- @translators This is the time in the morning using a 12-hour clock (%_I is the hour, %M the minute).
- return os.date(_("%_I:%M AM"), seconds)
- else
- -- @translators This is the time in the morning using a 12-hour clock (%-I is the hour, %M the minute).
- return os.date(_("%-I:%M AM"), seconds)
- end
- else
- if pad_with_spaces then
- -- @translators This is the time in the afternoon using a 12-hour clock (%_I is the hour, %M the minute).
- return os.date(_("%_I:%M PM"), seconds)
- else
- -- @translators This is the time in the afternoon using a 12-hour clock (%-I is the hour, %M the minute).
- return os.date(_("%-I:%M PM"), seconds)
- end
- end
- else
- if pad_with_spaces then
- -- @translators This is the time using a 24-hour clock (%_H is the hour, %M the minute).
- return os.date(_("%_H:%M"), seconds)
- else
- -- @translators This is the time using a 24-hour clock (%-H is the hour, %M the minute).
- return os.date(_("%-H:%M"), seconds)
- end
- end
- end
-end
-
---- Converts timestamp to a date string
----- @int seconds number of seconds
----- @bool twelve_hour_clock
----- @treturn string date string
-function util.secondsToDate(seconds, twelve_hour_clock)
- local BD = require("ui/bidi")
- -- In order to keep stuff aligned, we'll want to *keep* the padding, but using blanks instead of zeroes.
- local time = util.secondsToHour(seconds, twelve_hour_clock, true)
- -- @translators This is the date (%Y is the year, %m the month, %d the day)
- local day = os.date(_("%Y-%m-%d"), seconds)
- return BD.wrap(day) .. " " .. BD.wrap(time)
-end
-
--[[--
Compares values in two different tables.
diff --git a/plugins/autodim.koplugin/main.lua b/plugins/autodim.koplugin/main.lua
index eaec00a20..d52baa181 100644
--- a/plugins/autodim.koplugin/main.lua
+++ b/plugins/autodim.koplugin/main.lua
@@ -10,8 +10,8 @@ local SpinWidget = require("ui/widget/spinwidget")
local UIManager = require("ui/uimanager")
local WidgetContainer = require("ui/widget/container/widgetcontainer")
local TrapWidget = require("ui/widget/trapwidget")
+local datetime = require("datetime")
local time = require("ui/time")
-local util = require("util")
local _ = require("gettext")
local C_ = _.pgettext
local Powerd = Device.powerd
@@ -55,7 +55,7 @@ function AutoDim:getAutoDimMenu()
text_func = function()
return self.autodim_starttime_m <= 0 and _("Idle time for dimmer") or
T(_("Idle time for dimmer: %1"),
- util.secondsToClockDuration("modern", self.autodim_starttime_m * 60, false, true, false, true))
+ datetime.secondsToClockDuration("modern", self.autodim_starttime_m * 60, false, true, false, true))
end,
checked_func = function() return self.autodim_starttime_m > 0 end,
callback = function(touchmenu_instance)
@@ -94,7 +94,7 @@ function AutoDim:getAutoDimMenu()
{
text_func = function()
return T(_("Dimmer duration: %1"),
- util.secondsToClockDuration("modern", self.autodim_duration_s, false, true, false, true))
+ datetime.secondsToClockDuration("modern", self.autodim_duration_s, false, true, false, true))
end,
enabled_func = function() return self.autodim_starttime_m > 0 end,
callback = function(touchmenu_instance)
diff --git a/plugins/autosuspend.koplugin/main.lua b/plugins/autosuspend.koplugin/main.lua
index d4214e37c..f414bc6cc 100644
--- a/plugins/autosuspend.koplugin/main.lua
+++ b/plugins/autosuspend.koplugin/main.lua
@@ -6,15 +6,15 @@ if not Device:canSuspend() then
end
local Event = require("ui/event")
+local Math = require("optmath")
local NetworkMgr = require("ui/network/manager")
local PluginShare = require("pluginshare")
local UIManager = require("ui/uimanager")
local WidgetContainer = require("ui/widget/container/widgetcontainer")
+local datetime = require("datetime")
local logger = require("logger")
-local util = require("util")
local time = require("ui/time")
local _ = require("gettext")
-local Math = require("optmath")
local T = require("ffi/util").template
local default_autoshutdown_timeout_seconds = 3*24*60*60 -- three days
@@ -427,14 +427,14 @@ function AutoSuspend:pickTimeoutValue(touchmenu_instance, title, info, setting,
self:_start()
end
if touchmenu_instance then touchmenu_instance:updateItems() end
- local time_string = util.secondsToClockDuration("modern", self[setting],
+ local time_string = datetime.secondsToClockDuration("modern", self[setting],
time_scale == 2 or time_scale == 1, true, true)
UIManager:show(InfoMessage:new{
text = T(_("%1: %2"), title, time_string),
timeout = 3,
})
end,
- default_value = util.secondsToClockDuration("modern", default_value,
+ default_value = datetime.secondsToClockDuration("modern", default_value,
time_scale == 2 or time_scale == 1, true, true),
default_callback = function()
local day, hour, min, sec -- luacheck: ignore 431
@@ -481,7 +481,7 @@ function AutoSuspend:addToMainMenu(menu_items)
end,
text_func = function()
if self.auto_suspend_timeout_seconds and self.auto_suspend_timeout_seconds > 0 then
- local time_string = util.secondsToClockDuration("modern",
+ local time_string = datetime.secondsToClockDuration("modern",
self.auto_suspend_timeout_seconds, true, true, true)
return T(_("Autosuspend timeout: %1"), time_string)
else
@@ -507,7 +507,7 @@ function AutoSuspend:addToMainMenu(menu_items)
end,
text_func = function()
if self.autoshutdown_timeout_seconds and self.autoshutdown_timeout_seconds > 0 then
- local time_string = util.secondsToClockDuration("modern", self.autoshutdown_timeout_seconds,
+ local time_string = datetime.secondsToClockDuration("modern", self.autoshutdown_timeout_seconds,
true, true, true)
return T(_("Autoshutdown timeout: %1"), time_string)
else
@@ -546,7 +546,7 @@ Upon user input, the device needs a certain amount of time to wake up. Generally
end,
text_func = function()
if self.auto_standby_timeout_seconds and self.auto_standby_timeout_seconds > 0 then
- local time_string = util.secondsToClockDuration("modern", self.auto_standby_timeout_seconds,
+ local time_string = datetime.secondsToClockDuration("modern", self.auto_standby_timeout_seconds,
false, true, true, true)
return T(_("Autostandby timeout: %1"), time_string)
else
diff --git a/plugins/autoturn.koplugin/main.lua b/plugins/autoturn.koplugin/main.lua
index 204632d69..1184968ef 100644
--- a/plugins/autoturn.koplugin/main.lua
+++ b/plugins/autoturn.koplugin/main.lua
@@ -3,9 +3,9 @@ local Event = require("ui/event")
local PluginShare = require("pluginshare")
local UIManager = require("ui/uimanager")
local WidgetContainer = require("ui/widget/container/widgetcontainer")
+local datetime = require("datetime")
local logger = require("logger")
local time = require("ui/time")
-local util = require("util")
local _ = require("gettext")
local T = require("ffi/util").template
@@ -67,7 +67,7 @@ function AutoTurn:_start()
local text
if self.autoturn_distance == 1 then
- local time_string = util.secondsToClockDuration("modern", self.autoturn_sec, false, true, true, true)
+ local time_string = datetime.secondsToClockDuration("modern", self.autoturn_sec, false, true, true, true)
text = T(_("Autoturn is now active and will automatically turn the page every %1."), time_string)
else
text = T(_("Autoturn is now active and will automatically scroll %1 % of the page every %2 seconds."),
@@ -141,7 +141,7 @@ function AutoTurn:addToMainMenu(menu_items)
menu_items.autoturn = {
sorting_hint = "navi",
text_func = function()
- local time_string = util.secondsToClockDuration("modern", self.autoturn_sec, false, true, true, true)
+ local time_string = datetime.secondsToClockDuration("modern", self.autoturn_sec, false, true, true, true)
return self:_enabled() and T(_("Autoturn: %1"), time_string) or _("Autoturn")
end,
checked_func = function() return self:_enabled() end,
diff --git a/plugins/autowarmth.koplugin/main.lua b/plugins/autowarmth.koplugin/main.lua
index 7c2935cb7..d2b45664b 100644
--- a/plugins/autowarmth.koplugin/main.lua
+++ b/plugins/autowarmth.koplugin/main.lua
@@ -27,7 +27,7 @@ local C_ = _.pgettext
local Powerd = Device.powerd
local T = FFIUtil.template
local Screen = require("device").screen
-local util = require("util")
+local datetime = require("datetime")
local activate_sun = 1
local activate_schedule = 2
@@ -519,7 +519,7 @@ function AutoWarmth:hoursToClock(hours)
if hours then
hours = hours % 24 * 3600 + 0.01 -- round up, due to reduced precision in settings.reader.lua
end
- return util.secondsToClock(hours, self.easy_mode)
+ return datetime.secondsToClock(hours, self.easy_mode)
end
function AutoWarmth:addToMainMenu(menu_items)
diff --git a/plugins/batterystat.koplugin/main.lua b/plugins/batterystat.koplugin/main.lua
index b26b59ba4..2ce81156a 100644
--- a/plugins/batterystat.koplugin/main.lua
+++ b/plugins/batterystat.koplugin/main.lua
@@ -6,9 +6,9 @@ local LuaSettings = require("luasettings")
local PowerD = require("device"):getPowerDevice()
local UIManager = require("ui/uimanager")
local WidgetContainer = require("ui/widget/container/widgetcontainer")
+local datetime = require("datetime")
local dbg = require("dbg")
local time = require("ui/time")
-local util = require("util")
local _ = require("gettext")
local T = require("ffi/util").template
@@ -81,7 +81,7 @@ end
local function duration(number)
local duration_fmt = G_reader_settings:readSetting("duration_format", "classic")
return type(number) ~= "number" and number or
- util.secondsToClockDuration(duration_fmt, number, true, true, true)
+ datetime.secondsToClockDuration(duration_fmt, number, true, true, true)
end
function Usage:dump(kv_pairs, id)
diff --git a/plugins/readtimer.koplugin/main.lua b/plugins/readtimer.koplugin/main.lua
index 45d8d0c50..a27db1967 100644
--- a/plugins/readtimer.koplugin/main.lua
+++ b/plugins/readtimer.koplugin/main.lua
@@ -3,7 +3,7 @@ local InfoMessage = require("ui/widget/infomessage")
local UIManager = require("ui/uimanager")
local WidgetContainer = require("ui/widget/container/widgetcontainer")
local logger = require("logger")
-local util = require("util")
+local datetime = require("datetime")
local _ = require("gettext")
local T = require("ffi/util").template
@@ -70,7 +70,7 @@ function ReadTimer:addToMainMenu(menu_items)
if self:scheduled() then
local user_duration_format = G_reader_settings:readSetting("duration_format")
return T(_("Read timer (%1)"),
- util.secondsToClockDuration(user_duration_format, self:remaining(), false))
+ datetime.secondsToClockDuration(user_duration_format, self:remaining(), false))
else
return _("Read timer")
end
@@ -107,7 +107,7 @@ function ReadTimer:addToMainMenu(menu_items)
-- @translators %1:%2 is a clock time (HH:MM), %3 is a duration
text = T(_("Timer set for %1:%2.\n\nThat's %3 from now."),
string.format("%02d", time.hour), string.format("%02d", time.min),
- util.secondsToClockDuration(user_duration_format, seconds, false)),
+ datetime.secondsToClockDuration(user_duration_format, seconds, false)),
timeout = 5,
})
else
@@ -151,7 +151,7 @@ function ReadTimer:addToMainMenu(menu_items)
UIManager:show(InfoMessage:new{
-- @translators This is a duration
text = T(_("Timer will expire in %1."),
- util.secondsToClockDuration(user_duration_format, seconds, true)),
+ datetime.secondsToClockDuration(user_duration_format, seconds, true)),
timeout = 5,
})
remain_time = {time.hour, time.min}
diff --git a/plugins/statistics.koplugin/calendarview.lua b/plugins/statistics.koplugin/calendarview.lua
index 08b37cdd5..4058b5f96 100644
--- a/plugins/statistics.koplugin/calendarview.lua
+++ b/plugins/statistics.koplugin/calendarview.lua
@@ -1,3 +1,4 @@
+
local BD = require("ui/bidi")
local Blitbuffer = require("ffi/blitbuffer")
local BottomContainer = require("ui/widget/container/bottomcontainer")
diff --git a/plugins/statistics.koplugin/main.lua b/plugins/statistics.koplugin/main.lua
index 1a31f9da6..3b04f5a92 100644
--- a/plugins/statistics.koplugin/main.lua
+++ b/plugins/statistics.koplugin/main.lua
@@ -17,6 +17,7 @@ local SQ3 = require("lua-ljsqlite3/init")
local SyncService = require("frontend/apps/cloudstorage/syncservice")
local UIManager = require("ui/uimanager")
local Widget = require("ui/widget/widget")
+local datetime = require("datetime")
local lfs = require("libs/libkoreader-lfs")
local logger = require("logger")
local util = require("util")
@@ -75,43 +76,6 @@ local ReaderStatistics = Widget:extend{
data = nil, -- table
}
-local weekDays = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" } -- in Lua wday order
-
-local shortDayOfWeekTranslation = {
- ["Mon"] = _("Mon"),
- ["Tue"] = _("Tue"),
- ["Wed"] = _("Wed"),
- ["Thu"] = _("Thu"),
- ["Fri"] = _("Fri"),
- ["Sat"] = _("Sat"),
- ["Sun"] = _("Sun"),
-}
-
-local longDayOfWeekTranslation = {
- ["Mon"] = _("Monday"),
- ["Tue"] = _("Tuesday"),
- ["Wed"] = _("Wednesday"),
- ["Thu"] = _("Thursday"),
- ["Fri"] = _("Friday"),
- ["Sat"] = _("Saturday"),
- ["Sun"] = _("Sunday"),
-}
-
-local monthTranslation = {
- ["January"] = _("January"),
- ["February"] = _("February"),
- ["March"] = _("March"),
- ["April"] = _("April"),
- ["May"] = _("May"),
- ["June"] = _("June"),
- ["July"] = _("July"),
- ["August"] = _("August"),
- ["September"] = _("September"),
- ["October"] = _("October"),
- ["November"] = _("November"),
- ["December"] = _("December"),
-}
-
function ReaderStatistics:isDocless()
return self.ui == nil or self.ui.document == nil or self.ui.document.is_pic == true
end
@@ -1023,26 +987,26 @@ The max value ensures a page you stay on for a long time (because you fell aslee
{
text_func = function()
return T(_("Calendar weeks start on %1"),
- longDayOfWeekTranslation[weekDays[self.settings.calendar_start_day_of_week]])
+ datetime.shortDayOfWeekToLongTranslation[datetime.weekDays[self.settings.calendar_start_day_of_week]])
end,
sub_item_table = {
{ -- Friday (Bangladesh and Maldives)
- text = longDayOfWeekTranslation[weekDays[6]],
+ text = datetime.shortDayOfWeekToLongTranslation[datetime.weekDays[6]],
checked_func = function() return self.settings.calendar_start_day_of_week == 6 end,
callback = function() self.settings.calendar_start_day_of_week = 6 end
},
{ -- Saturday (some Middle East countries)
- text = longDayOfWeekTranslation[weekDays[7]],
+ text = datetime.shortDayOfWeekToLongTranslation[datetime.weekDays[7]],
checked_func = function() return self.settings.calendar_start_day_of_week == 7 end,
callback = function() self.settings.calendar_start_day_of_week = 7 end
},
{ -- Sunday
- text = longDayOfWeekTranslation[weekDays[1]],
+ text = datetime.shortDayOfWeekToLongTranslation[datetime.weekDays[1]],
checked_func = function() return self.settings.calendar_start_day_of_week == 1 end,
callback = function() self.settings.calendar_start_day_of_week = 1 end
},
{ -- Monday
- text = longDayOfWeekTranslation[weekDays[2]],
+ text = datetime.shortDayOfWeekToLongTranslation[datetime.weekDays[2]],
checked_func = function() return self.settings.calendar_start_day_of_week == 2 end,
callback = function() self.settings.calendar_start_day_of_week = 2 end
},
@@ -1491,27 +1455,27 @@ function ReaderStatistics:getCurrentStat()
return {
-- Global statistics (may consider other books than current book)
-- since last resume
- { _("Time spent reading this session"), util.secondsToClockDuration(user_duration_format, current_duration, false) },
+ { _("Time spent reading this session"), datetime.secondsToClockDuration(user_duration_format, current_duration, false) },
{ _("Pages read this session"), tonumber(current_pages) },
-- today
- { _("Time spent reading today"), util.secondsToClockDuration(user_duration_format, today_duration, false) },
+ { _("Time spent reading today"), datetime.secondsToClockDuration(user_duration_format, today_duration, false) },
{ _("Pages read today"), tonumber(today_pages), separator = true },
-- Current book statistics
-- Includes re-reads
- { _("Total time spent on this book"), util.secondsToClockDuration(user_duration_format, total_time_book, false) },
+ { _("Total time spent on this book"), datetime.secondsToClockDuration(user_duration_format, total_time_book, false) },
-- Capped to self.settings.max_sec per distinct page
- { _("Time spent reading this book"), util.secondsToClockDuration(user_duration_format, book_read_time, false) },
+ { _("Time spent reading this book"), datetime.secondsToClockDuration(user_duration_format, book_read_time, false) },
-- per days
{ _("Reading started"), os.date("%Y-%m-%d (%H:%M)", tonumber(first_open))},
{ _("Days reading this book"), tonumber(total_days) },
- { _("Average time per day"), util.secondsToClockDuration(user_duration_format, book_read_time/tonumber(total_days), false) },
+ { _("Average time per day"), datetime.secondsToClockDuration(user_duration_format, book_read_time/tonumber(total_days), false) },
-- per page (% read)
- { _("Average time per page"), util.secondsToClockDuration(user_duration_format, self.avg_time, false) },
+ { _("Average time per page"), datetime.secondsToClockDuration(user_duration_format, self.avg_time, false) },
{ _("Pages read"), string.format("%d (%d%%)", total_read_pages, Math.round(100*total_read_pages/self.data.pages)) },
-- current page (% completed)
{ _("Current page/Total pages"), string.format("%d/%d (%d%%)", self.curr_page, self.data.pages, Math.round(100*self.curr_page/self.data.pages)) },
-- estimation, from current page to end of book
- { _("Estimated time to read"), estimates_valid and util.secondsToClockDuration(user_duration_format, time_to_read, false) or _("N/A") },
+ { _("Estimated time to read"), estimates_valid and datetime.secondsToClockDuration(user_duration_format, time_to_read, false) or _("N/A") },
{ _("Estimated reading finished"), estimates_valid and
T(N_("%1 (1 day)", "%1 (%2 days)", estimate_days_to_read), estimate_end_of_read_date, estimate_days_to_read)
or _("N/A") },
@@ -1612,10 +1576,10 @@ function ReaderStatistics:getBookStat(id_book)
{ _("Reading started"), os.date("%Y-%m-%d (%H:%M)", tonumber(first_open))},
{ _("Last read"), os.date("%Y-%m-%d (%H:%M)", tonumber(last_open))},
{ _("Days reading this book"), tonumber(total_days) },
- { _("Total time spent on this book"), util.secondsToClockDuration(user_duration_format, total_time_book, false) },
- { _("Time spent reading this book"), util.secondsToClockDuration(user_duration_format, book_read_time, false) },
- { _("Average time per day"), util.secondsToClockDuration(user_duration_format, book_read_time/tonumber(total_days), false) },
- { _("Average time per page"), util.secondsToClockDuration(user_duration_format, avg_time_per_page, false) },
+ { _("Total time spent on this book"), datetime.secondsToClockDuration(user_duration_format, total_time_book, false) },
+ { _("Time spent reading this book"), datetime.secondsToClockDuration(user_duration_format, book_read_time, false) },
+ { _("Average time per day"), datetime.secondsToClockDuration(user_duration_format, book_read_time/tonumber(total_days), false) },
+ { _("Average time per page"), datetime.secondsToClockDuration(user_duration_format, avg_time_per_page, false) },
{ _("Pages read"), string.format("%d (%d%%)", total_read_pages, Math.round(100*total_read_pages/pages)) },
{ _("Last read page/Total pages"), string.format("%d/%d (%d%%)", last_page, pages, Math.round(100*last_page/pages)) },
{ _("Highlights"), highlights, separator = true },
@@ -1813,13 +1777,13 @@ function ReaderStatistics:getDatesFromAll(sdays, ptype, book_mode)
if ptype == "daily_weekday" then
date_text = string.format("%s (%s)",
os.date("%Y-%m-%d", timestamp),
- shortDayOfWeekTranslation[os.date("%a", timestamp)])
+ datetime.shortDayOfWeekTranslation[os.date("%a", timestamp)])
elseif ptype == "daily" then
date_text = result_book[1][i]
elseif ptype == "weekly" then
date_text = T(_("%1 Week %2"), os.date("%Y", timestamp), os.date(" %W", timestamp))
elseif ptype == "monthly" then
- date_text = monthTranslation[os.date("%B", timestamp)] .. os.date(" %Y", timestamp)
+ date_text = datetime.longMonthTranslation[os.date("%B", timestamp)] .. os.date(" %Y", timestamp)
else
date_text = result_book[1][i]
end
@@ -1839,7 +1803,7 @@ function ReaderStatistics:getDatesFromAll(sdays, ptype, book_mode)
local stop_month = os.time{year=year_end, month=month_end, day=1, hour=0, min=0 }
table.insert(results, {
date_text,
- T(_("Pages: (%1) Time: %2"), tonumber(result_book[2][i]), util.secondsToClockDuration(user_duration_format, tonumber(result_book[3][i]), false)),
+ T(_("Pages: (%1) Time: %2"), tonumber(result_book[2][i]), datetime.secondsToClockDuration(user_duration_format, tonumber(result_book[3][i]), false)),
callback = function()
self:callbackMonthly(start_month, stop_month, date_text, book_mode)
end,
@@ -1853,7 +1817,7 @@ function ReaderStatistics:getDatesFromAll(sdays, ptype, book_mode)
begin_week = begin_week - weekday * 86400
table.insert(results, {
date_text,
- T(_("Pages: (%1) Time: %2"), tonumber(result_book[2][i]), util.secondsToClockDuration(user_duration_format, tonumber(result_book[3][i]), false)),
+ T(_("Pages: (%1) Time: %2"), tonumber(result_book[2][i]), datetime.secondsToClockDuration(user_duration_format, tonumber(result_book[3][i]), false)),
callback = function()
self:callbackWeekly(begin_week, begin_week + 7 * 86400, date_text, book_mode)
end,
@@ -1864,7 +1828,7 @@ function ReaderStatistics:getDatesFromAll(sdays, ptype, book_mode)
- 60 * tonumber(string.sub(time_book,3,4)) - tonumber(string.sub(time_book,5,6))
table.insert(results, {
date_text,
- T(_("Pages: (%1) Time: %2"), tonumber(result_book[2][i]), util.secondsToClockDuration(user_duration_format, tonumber(result_book[3][i]), false)),
+ T(_("Pages: (%1) Time: %2"), tonumber(result_book[2][i]), datetime.secondsToClockDuration(user_duration_format, tonumber(result_book[3][i]), false)),
callback = function()
self:callbackDaily(begin_day, begin_day + 86400, date_text)
end,
@@ -1905,7 +1869,7 @@ function ReaderStatistics:getDaysFromPeriod(period_begin, period_end)
day=string.sub(result_book[1][i],9,10), hour=0, min=0, sec=0 }
table.insert(results, {
result_book[1][i],
- T(_("Pages: (%1) Time: %2"), tonumber(result_book[2][i]), util.secondsToClockDuration(user_duration_format, tonumber(result_book[3][i]), false)),
+ T(_("Pages: (%1) Time: %2"), tonumber(result_book[2][i]), datetime.secondsToClockDuration(user_duration_format, tonumber(result_book[3][i]), false)),
callback = function()
local kv = self.kv
UIManager:close(kv)
@@ -1949,7 +1913,7 @@ function ReaderStatistics:getBooksFromPeriod(period_begin, period_end, callback_
for i=1, #result_book.title do
table.insert(results, {
result_book[1][i],
- T(_("%1 (%2)"), util.secondsToClockDuration(user_duration_format, tonumber(result_book[2][i]), false), tonumber(result_book[3][i])),
+ T(_("%1 (%2)"), datetime.secondsToClockDuration(user_duration_format, tonumber(result_book[2][i]), false), tonumber(result_book[3][i])),
book_id = tonumber(result_book[4][i]),
callback = function()
local kv = self.kv
@@ -2056,7 +2020,7 @@ function ReaderStatistics:getDatesForBook(id_book)
for i=1, #result_book.dates do
table.insert(results, {
result_book[1][i],
- T(_("Pages: (%1) Time: %2"), tonumber(result_book[2][i]), util.secondsToClockDuration(user_duration_format, tonumber(result_book[3][i]), false)),
+ T(_("Pages: (%1) Time: %2"), tonumber(result_book[2][i]), datetime.secondsToClockDuration(user_duration_format, tonumber(result_book[3][i]), false)),
hold_callback = function(kv_page, kv_item)
self:resetStatsForBookForPeriod(id_book, result_book[4][i], result_book[5][i], result_book[1][i], function()
kv_page:removeKeyValueItem(kv_item) -- Reset, refresh what's displayed
@@ -2155,7 +2119,7 @@ function ReaderStatistics:getTotalStats()
end
table.insert(total_stats, {
book_title,
- util.secondsToClockDuration(user_duration_format, total_time_book, false),
+ datetime.secondsToClockDuration(user_duration_format, total_time_book, false),
callback = function()
local kv = self.kv
UIManager:close(self.kv)
@@ -2176,7 +2140,7 @@ function ReaderStatistics:getTotalStats()
end
conn:close()
- return T(_("Total time spent reading: %1"), util.secondsToClockDuration(user_duration_format, total_books_time, false)), total_stats
+ return T(_("Total time spent reading: %1"), datetime.secondsToClockDuration(user_duration_format, total_books_time, false)), total_stats
end
function ReaderStatistics:genResetBookSubItemTable()
@@ -2256,7 +2220,7 @@ function ReaderStatistics:resetPerBook()
if id_book ~= self.id_curr_book then
table.insert(total_stats, {
book_title,
- util.secondsToClockDuration(user_duration_format, total_time_book, false),
+ datetime.secondsToClockDuration(user_duration_format, total_time_book, false),
id_book,
callback = function(kv_page, kv_item)
UIManager:show(ConfirmBox:new{
@@ -2599,9 +2563,9 @@ function ReaderStatistics:onShowCalendarView()
local CalendarView = require("calendarview")
UIManager:show(CalendarView:new{
reader_statistics = self,
- monthTranslation = monthTranslation,
- shortDayOfWeekTranslation = shortDayOfWeekTranslation,
- longDayOfWeekTranslation = longDayOfWeekTranslation,
+ monthTranslation = datetime.longMonthTranslation,
+ shortDayOfWeekTranslation = datetime.shortDayOfWeekTranslation,
+ longDayOfWeekTranslation = datetime.shortDayOfWeekToLongTranslation,
start_day_of_week = self.settings.calendar_start_day_of_week,
nb_book_spans = self.settings.calendar_nb_book_spans,
show_hourly_histogram = self.settings.calendar_show_histogram,
@@ -2616,7 +2580,7 @@ function ReaderStatistics:onShowCalendarDayView()
local title_callback = function(this)
local day = os.date("%Y-%m-%d", this.day_ts + 10800) -- use 03:00 to determine date (summer time change)
local date = os.date("*t", this.day_ts + 10800)
- return string.format("%s (%s)", day, longDayOfWeekTranslation[CalendarView.weekdays[date.wday]])
+ return string.format("%s (%s)", day, datetime.longDayOfWeekTranslation[CalendarView.weekdays[date.wday]])
end
CalendarView:showCalendarDayView(self, title_callback)
end
diff --git a/plugins/statistics.koplugin/readerprogress.lua b/plugins/statistics.koplugin/readerprogress.lua
index ee145a05e..928ac9ee5 100644
--- a/plugins/statistics.koplugin/readerprogress.lua
+++ b/plugins/statistics.koplugin/readerprogress.lua
@@ -18,7 +18,7 @@ local TitleBar = require("ui/widget/titlebar")
local UIManager = require("ui/uimanager")
local VerticalGroup = require("ui/widget/verticalgroup")
local VerticalSpan = require("ui/widget/verticalspan")
-local util = require("util")
+local datetime = require("datetime")
local _ = require("gettext")
local Screen = Device.screen
@@ -251,7 +251,7 @@ function ReaderProgress:genWeekStats(stats_day)
dimen = Geom:new{ w = self.screen_width , h = height * (1/3) },
TextWidget:new{
padding = Size.padding.small,
- text = date_format_show .. " - " .. util.secondsToClockDuration(user_duration_format, select_day_time, true),
+ text = date_format_show .. " - " .. datetime.secondsToClockDuration(user_duration_format, select_day_time, true),
face = Font:getFace("smallffont"),
},
},
@@ -345,7 +345,7 @@ function ReaderProgress:genSummaryDay(width)
CenterContainer:new{
dimen = Geom:new{ w = tile_width, h = tile_height },
TextWidget:new{
- text = util.secondsToClockDuration(user_duration_format, self.current_duration, true),
+ text = datetime.secondsToClockDuration(user_duration_format, self.current_duration, true),
face = self.medium_font_face,
},
},
@@ -359,7 +359,7 @@ function ReaderProgress:genSummaryDay(width)
CenterContainer:new{
dimen = Geom:new{ w = tile_width, h = tile_height },
TextWidget:new{
- text = util.secondsToClockDuration(user_duration_format, self.today_duration, true),
+ text = datetime.secondsToClockDuration(user_duration_format, self.today_duration, true),
face = self.medium_font_face,
},
},
@@ -447,7 +447,7 @@ function ReaderProgress:genSummaryWeek(width)
CenterContainer:new{
dimen = Geom:new{ w = tile_width, h = tile_height },
TextWidget:new{
- text = util.secondsToClockDuration(user_duration_format, math.floor(total_time), true),
+ text = datetime.secondsToClockDuration(user_duration_format, math.floor(total_time), true),
face = self.medium_font_face,
},
},
@@ -461,7 +461,7 @@ function ReaderProgress:genSummaryWeek(width)
CenterContainer:new{
dimen = Geom:new{ w = tile_width, h = tile_height },
TextWidget:new{
- text = util.secondsToClockDuration(user_duration_format, math.floor(total_time) * (1/7), true),
+ text = datetime.secondsToClockDuration(user_duration_format, math.floor(total_time) * (1/7), true),
face = self.medium_font_face,
}
}
diff --git a/plugins/systemstat.koplugin/main.lua b/plugins/systemstat.koplugin/main.lua
index 2fea900b5..30bbcca58 100644
--- a/plugins/systemstat.koplugin/main.lua
+++ b/plugins/systemstat.koplugin/main.lua
@@ -4,6 +4,7 @@ local KeyValuePage = require("ui/widget/keyvaluepage")
local Math = require("optmath")
local UIManager = require("ui/uimanager")
local WidgetContainer = require("ui/widget/container/widgetcontainer")
+local datetime = require("datetime")
local time = require("ui/time")
local util = require("util")
local _ = require("gettext")
@@ -69,21 +70,21 @@ function SystemStat:appendCounters()
standby = Device.total_standby_time
end
self:put({" " .. _("Up time"),
- util.secondsToClockDuration("", time.to_s(uptime), false, true, true)})
+ datetime.secondsToClockDuration("", time.to_s(uptime), false, true, true)})
if Device:canSuspend() or Device:canStandby() then
local awake = uptime - suspend - standby
self:put({" " .. _("Time spent awake"),
- util.secondsToClockDuration("", time.to_s(awake), false, true, true)
+ datetime.secondsToClockDuration("", time.to_s(awake), false, true, true)
.. " (" .. Math.round((awake / uptime) * 100) .. "%)"})
end
if Device:canSuspend() then
self:put({" " .. _("Time in suspend"),
- util.secondsToClockDuration("", time.to_s(suspend), false, true, true)
+ datetime.secondsToClockDuration("", time.to_s(suspend), false, true, true)
.. " (" .. Math.round((suspend / uptime) * 100) .. "%)"})
end
if Device:canStandby() then
self:put({" " .. _("Time in standby"),
- util.secondsToClockDuration("", time.to_s(standby), false, true, true)
+ datetime.secondsToClockDuration("", time.to_s(standby), false, true, true)
.. " (" .. Math.round((standby / uptime) * 100) .. "%)"})
end
self:put({_("Counters"), ""})
diff --git a/spec/unit/datetime_spec.lua b/spec/unit/datetime_spec.lua
new file mode 100644
index 000000000..cd915671c
--- /dev/null
+++ b/spec/unit/datetime_spec.lua
@@ -0,0 +1,188 @@
+describe("datetime module", function()
+ local datetime
+ setup(function()
+ require("commonrequire")
+ datetime = require("datetime")
+ end)
+
+ describe("secondsToClock()", function()
+ it("should convert seconds to 00:00 format", function()
+ assert.is_equal("00:00",
+ datetime.secondsToClock(0, true))
+ assert.is_equal("00:01",
+ datetime.secondsToClock(60, true))
+ end)
+ it("should round seconds to minutes in 00:00 format", function()
+ assert.is_equal("00:01",
+ datetime.secondsToClock(89, true))
+ assert.is_equal("00:02",
+ datetime.secondsToClock(90, true))
+ assert.is_equal("00:02",
+ datetime.secondsToClock(110, true))
+ assert.is_equal("00:02",
+ datetime.secondsToClock(120, true))
+ assert.is_equal("01:00",
+ datetime.secondsToClock(3600, true))
+ assert.is_equal("01:00",
+ datetime.secondsToClock(3599, true))
+ assert.is_equal("01:00",
+ datetime.secondsToClock(3570, true))
+ assert.is_equal("00:59",
+ datetime.secondsToClock(3569, true))
+ end)
+ it("should convert seconds to 00:00:00 format", function()
+ assert.is_equal("00:00:00",
+ datetime.secondsToClock(0))
+ assert.is_equal("00:01:00",
+ datetime.secondsToClock(60))
+ assert.is_equal("00:01:29",
+ datetime.secondsToClock(89))
+ assert.is_equal("00:01:30",
+ datetime.secondsToClock(90))
+ assert.is_equal("00:01:50",
+ datetime.secondsToClock(110))
+ assert.is_equal("00:02:00",
+ datetime.secondsToClock(120))
+ end)
+ end)
+
+ describe("secondsToHClock()", function()
+ it("should convert seconds to 0'00'' format", function()
+ assert.is_equal("0'",
+ datetime.secondsToHClock(0, true))
+ assert.is_equal("0'",
+ datetime.secondsToHClock(29, true))
+ assert.is_equal("1'",
+ datetime.secondsToHClock(60, true))
+ end)
+ it("should round seconds to minutes in 0h00' format", function()
+ assert.is_equal("1'",
+ datetime.secondsToHClock(89, true))
+ assert.is_equal("2'",
+ datetime.secondsToHClock(90, true))
+ assert.is_equal("2'",
+ datetime.secondsToHClock(110, true))
+ assert.is_equal("2'",
+ datetime.secondsToHClock(120, true))
+ assert.is_equal("1h00'",
+ datetime.secondsToHClock(3600, true))
+ assert.is_equal("1h00'",
+ datetime.secondsToHClock(3599, true))
+ assert.is_equal("1h00'",
+ datetime.secondsToHClock(3570, true))
+ assert.is_equal("59'",
+ datetime.secondsToHClock(3569, true))
+ assert.is_equal("10h01'",
+ datetime.secondsToHClock(36060, true))
+ end)
+ it("should round seconds to minutes in 0h00m format", function()
+ assert.is_equal("1m",
+ datetime.secondsToHClock(89, true, true))
+ assert.is_equal("2m",
+ datetime.secondsToHClock(90, true, true))
+ assert.is_equal("2m",
+ datetime.secondsToHClock(110, true, true))
+ assert.is_equal("1h00m",
+ datetime.secondsToHClock(3600, true, true))
+ assert.is_equal("1h00m",
+ datetime.secondsToHClock(3599, true, true))
+ assert.is_equal("59m",
+ datetime.secondsToHClock(3569, true, true))
+ assert.is_equal("10h01m",
+ datetime.secondsToHClock(36060, true, true))
+ end)
+ it("should convert seconds to 0h00'00'' format", function()
+ assert.is_equal("0\"",
+ datetime.secondsToHClock(0))
+ assert.is_equal("1'00\"",
+ datetime.secondsToHClock(60))
+ assert.is_equal("1'29\"",
+ datetime.secondsToHClock(89))
+ assert.is_equal("1'30\"",
+ datetime.secondsToHClock(90))
+ assert.is_equal("1'50\"",
+ datetime.secondsToHClock(110))
+ assert.is_equal("2'00\"",
+ datetime.secondsToHClock(120))
+ end)
+ end)
+
+ describe("secondsToClockDuration()", function()
+ it("should change type based on format", function()
+ assert.is_equal("10h01m30s",
+ datetime.secondsToClockDuration("modern", 36090, false, true))
+ assert.is_equal("10:01:30",
+ datetime.secondsToClockDuration("classic", 36090, false))
+ assert.is_equal("10:01:30",
+ datetime.secondsToClockDuration("unknown", 36090, false))
+ assert.is_equal("10:01:30",
+ datetime.secondsToClockDuration(nil, 36090, false))
+ end)
+ it("should pass along withoutSeconds", function()
+ assert.is_equal("10h01m30s",
+ datetime.secondsToClockDuration("modern", 36090, false, true))
+ assert.is_equal("10h02m",
+ datetime.secondsToClockDuration("modern", 36090, true, true))
+ assert.is_equal("10:01:30",
+ datetime.secondsToClockDuration("classic", 36090, false))
+ assert.is_equal("10:02",
+ datetime.secondsToClockDuration("classic", 36090, true))
+ end)
+ it("should pass along hmsFormat for modern format", function()
+ assert.is_equal("10h01'30\"",
+ datetime.secondsToClockDuration("modern", 36090))
+ assert.is_equal("10h01m30s",
+ datetime.secondsToClockDuration("modern", 36090, false, true))
+ assert.is_equal("10h02m",
+ datetime.secondsToClockDuration("modern", 36090, true, true))
+ assert.is_equal("10h02'",
+ datetime.secondsToClockDuration("modern", 36090, true, false))
+ assert.is_equal("10:01:30",
+ datetime.secondsToClockDuration("classic", 36090, false, true))
+ assert.is_equal("10:01:30",
+ datetime.secondsToClockDuration("classic", 36090, false, false))
+ end)
+ end)
+
+ describe("secondsToDate()", function()
+ it("should deliver a date string", function()
+ local time = { year=2022, month=12, day=6, hour=13, min=30, sec=35 }
+ local time_s = os.time(time)
+
+ assert.is_equal("2022-12-06",
+ datetime.secondsToDate(time_s))
+ assert.is_equal("2022-12-07",
+ datetime.secondsToDate(time_s + 86400)) -- one day later
+ assert.is_equal("Tue Dec 06 2022",
+ datetime.secondsToDate(time_s, true))
+ assert.is_equal("Wed Dec 07 2022",
+ datetime.secondsToDate(time_s + 86400, true))
+ end)
+ end)
+ describe("secondsToDateTime()", function()
+ it("should should deliver a date and time string", function()
+ local time = { year=2022, month=11, day=20, hour=9, min=57, sec=39 }
+ local time_s = os.time(time)
+
+ assert.is_equal("2022-11-20 9:57",
+ datetime.secondsToDateTime(time_s))
+ assert.is_equal("2022-11-21 9:57",
+ datetime.secondsToDateTime(time_s + 86400))
+
+ assert.is_equal("2022-11-20 9:57 AM",
+ datetime.secondsToDateTime(time_s, true))
+ assert.is_equal("2022-11-21 9:57 AM",
+ datetime.secondsToDateTime(time_s + 86400, true))
+
+ assert.is_equal("Sun Nov 20 2022 9:57",
+ datetime.secondsToDateTime(time_s, false, true))
+ assert.is_equal("Mon Nov 21 2022 9:57",
+ datetime.secondsToDateTime(time_s + 86400, false, true))
+
+ assert.is_equal("Sun Nov 20 2022 9:57 AM",
+ datetime.secondsToDateTime(time_s, true, true))
+ assert.is_equal("Mon Nov 21 2022 9:57 AM",
+ datetime.secondsToDateTime(time_s + 86400, true, true))
+ end)
+ end)
+end)
diff --git a/spec/unit/util_spec.lua b/spec/unit/util_spec.lua
index 66d10bcda..9432bddcb 100644
--- a/spec/unit/util_spec.lua
+++ b/spec/unit/util_spec.lua
@@ -461,145 +461,6 @@ describe("util module", function()
end)
end)
- describe("secondsToClock()", function()
- it("should convert seconds to 00:00 format", function()
- assert.is_equal("00:00",
- util.secondsToClock(0, true))
- assert.is_equal("00:01",
- util.secondsToClock(60, true))
- end)
- it("should round seconds to minutes in 00:00 format", function()
- assert.is_equal("00:01",
- util.secondsToClock(89, true))
- assert.is_equal("00:02",
- util.secondsToClock(90, true))
- assert.is_equal("00:02",
- util.secondsToClock(110, true))
- assert.is_equal("00:02",
- util.secondsToClock(120, true))
- assert.is_equal("01:00",
- util.secondsToClock(3600, true))
- assert.is_equal("01:00",
- util.secondsToClock(3599, true))
- assert.is_equal("01:00",
- util.secondsToClock(3570, true))
- assert.is_equal("00:59",
- util.secondsToClock(3569, true))
- end)
- it("should convert seconds to 00:00:00 format", function()
- assert.is_equal("00:00:00",
- util.secondsToClock(0))
- assert.is_equal("00:01:00",
- util.secondsToClock(60))
- assert.is_equal("00:01:29",
- util.secondsToClock(89))
- assert.is_equal("00:01:30",
- util.secondsToClock(90))
- assert.is_equal("00:01:50",
- util.secondsToClock(110))
- assert.is_equal("00:02:00",
- util.secondsToClock(120))
- end)
- end)
-
- describe("secondsToHClock()", function()
- it("should convert seconds to 0'00'' format", function()
- assert.is_equal("0'",
- util.secondsToHClock(0, true))
- assert.is_equal("0'",
- util.secondsToHClock(29, true))
- assert.is_equal("1'",
- util.secondsToHClock(60, true))
- end)
- it("should round seconds to minutes in 0h00' format", function()
- assert.is_equal("1'",
- util.secondsToHClock(89, true))
- assert.is_equal("2'",
- util.secondsToHClock(90, true))
- assert.is_equal("2'",
- util.secondsToHClock(110, true))
- assert.is_equal("2'",
- util.secondsToHClock(120, true))
- assert.is_equal("1h00'",
- util.secondsToHClock(3600, true))
- assert.is_equal("1h00'",
- util.secondsToHClock(3599, true))
- assert.is_equal("1h00'",
- util.secondsToHClock(3570, true))
- assert.is_equal("59'",
- util.secondsToHClock(3569, true))
- assert.is_equal("10h01'",
- util.secondsToHClock(36060, true))
- end)
- it("should round seconds to minutes in 0h00m format", function()
- assert.is_equal("1m",
- util.secondsToHClock(89, true, true))
- assert.is_equal("2m",
- util.secondsToHClock(90, true, true))
- assert.is_equal("2m",
- util.secondsToHClock(110, true, true))
- assert.is_equal("1h00m",
- util.secondsToHClock(3600, true, true))
- assert.is_equal("1h00m",
- util.secondsToHClock(3599, true, true))
- assert.is_equal("59m",
- util.secondsToHClock(3569, true, true))
- assert.is_equal("10h01m",
- util.secondsToHClock(36060, true, true))
- end)
- it("should convert seconds to 0h00'00'' format", function()
- assert.is_equal("0\"",
- util.secondsToHClock(0))
- assert.is_equal("1'00\"",
- util.secondsToHClock(60))
- assert.is_equal("1'29\"",
- util.secondsToHClock(89))
- assert.is_equal("1'30\"",
- util.secondsToHClock(90))
- assert.is_equal("1'50\"",
- util.secondsToHClock(110))
- assert.is_equal("2'00\"",
- util.secondsToHClock(120))
- end)
- end)
-
- describe("secondsToClockDuration()", function()
- it("should change type based on format", function()
- assert.is_equal("10h01m30s",
- util.secondsToClockDuration("modern", 36090, false, true))
- assert.is_equal("10:01:30",
- util.secondsToClockDuration("classic", 36090, false))
- assert.is_equal("10:01:30",
- util.secondsToClockDuration("unknown", 36090, false))
- assert.is_equal("10:01:30",
- util.secondsToClockDuration(nil, 36090, false))
- end)
- it("should pass along withoutSeconds", function()
- assert.is_equal("10h01m30s",
- util.secondsToClockDuration("modern", 36090, false, true))
- assert.is_equal("10h02m",
- util.secondsToClockDuration("modern", 36090, true, true))
- assert.is_equal("10:01:30",
- util.secondsToClockDuration("classic", 36090, false))
- assert.is_equal("10:02",
- util.secondsToClockDuration("classic", 36090, true))
- end)
- it("should pass along hmsFormat for modern format", function()
- assert.is_equal("10h01'30\"",
- util.secondsToClockDuration("modern", 36090))
- assert.is_equal("10h01m30s",
- util.secondsToClockDuration("modern", 36090, false, true))
- assert.is_equal("10h02m",
- util.secondsToClockDuration("modern", 36090, true, true))
- assert.is_equal("10h02'",
- util.secondsToClockDuration("modern", 36090, true, false))
- assert.is_equal("10:01:30",
- util.secondsToClockDuration("classic", 36090, false, true))
- assert.is_equal("10:01:30",
- util.secondsToClockDuration("classic", 36090, false, false))
- end)
- end) -- end my changes
-
describe("urlEncode() and urlDecode", function()
it("should encode string", function()
assert.is_equal("Secret_Password123", util.urlEncode("Secret_Password123"))