Add utils::format_timespan() for formatting time lengths for user display
This commit is contained in:
parent
29d3cdd7d0
commit
37cca84684
4 changed files with 197 additions and 0 deletions
|
@ -11,6 +11,7 @@ tests/test_filesystem.cpp
|
|||
tests/test_formula_ai.cpp
|
||||
tests/test_formula_core.cpp
|
||||
tests/test_formula_function.cpp
|
||||
tests/test_formula_timespan.cpp
|
||||
tests/test_image_modifications.cpp
|
||||
tests/test_irdya_date.cpp
|
||||
tests/test_lexical_cast.cpp
|
||||
|
|
|
@ -279,6 +279,39 @@ std::string format_disjunct_list(const t_string& empty, const std::vector<t_stri
|
|||
return VGETTEXT("disjunct end^$prefix, or $last", {{"prefix", prefix}, {"last", elems.back()}});
|
||||
}
|
||||
|
||||
std::string format_timespan(std::time_t time)
|
||||
{
|
||||
if(time <= 0) {
|
||||
return _("timespan^expired");
|
||||
}
|
||||
|
||||
static const std::vector<std::tuple<std::time_t, const char*, const char*>> TIME_FACTORS{
|
||||
{ 31104000, N_("timespan^$num year"), N_("timespan^$num years") }, // 12 months
|
||||
{ 2592000, N_("timespan^$num month"), N_("timespan^$num months") }, // 30 days
|
||||
{ 604800, N_("timespan^$num week"), N_("timespan^$num weeks") },
|
||||
{ 86400, N_("timespan^$num day"), N_("timespan^$num days") },
|
||||
{ 3600, N_("timespan^$num hour"), N_("timespan^$num hours") },
|
||||
{ 60, N_("timespan^$num minute"), N_("timespan^$num minutes") },
|
||||
{ 1, N_("timespan^$num second"), N_("timespan^$num seconds") },
|
||||
};
|
||||
|
||||
std::vector<t_string> display_text;
|
||||
string_map i18n;
|
||||
|
||||
for(const auto& factor : TIME_FACTORS) {
|
||||
const int amount = time / std::get<0>(factor);
|
||||
|
||||
if(amount) {
|
||||
time -= std::get<0>(factor) * amount;
|
||||
i18n["num"] = std::to_string(amount);
|
||||
const auto fmt = amount == 1 ? std::get<1>(factor) : std::get<2>(factor);
|
||||
display_text.emplace_back(VGETTEXT(fmt, i18n));
|
||||
}
|
||||
}
|
||||
|
||||
return format_conjunct_list(_("timespan^expired"), display_text);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
std::string vgettext_impl(const char *domain
|
||||
|
|
|
@ -20,6 +20,8 @@
|
|||
|
||||
#include "serialization/string_utils.hpp"
|
||||
|
||||
#include <ctime>
|
||||
|
||||
class variable_set;
|
||||
|
||||
namespace utils {
|
||||
|
@ -74,6 +76,13 @@ std::string format_conjunct_list(const t_string& empty, const std::vector<t_stri
|
|||
*/
|
||||
std::string format_disjunct_list(const t_string& empty, const std::vector<t_string>& elems);
|
||||
|
||||
/**
|
||||
* Formats a timespan into human-readable text.
|
||||
* @param time The timespan in seconds.
|
||||
* @return A string such as "6 days, 12 hours, 4 minutes, 13 seconds". Years,
|
||||
* months and weeks are also considered.
|
||||
*/
|
||||
std::string format_timespan(std::time_t time);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
154
src/tests/test_formula_timespan.cpp
Normal file
154
src/tests/test_formula_timespan.cpp
Normal file
|
@ -0,0 +1,154 @@
|
|||
/*
|
||||
Copyright (C) 2019 by Iris Morelle <shadowm2006@gmail.com>
|
||||
Part of the Battle for Wesnoth Project https://www.wesnoth.org/
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY.
|
||||
|
||||
See the COPYING file for more details.
|
||||
*/
|
||||
|
||||
#include <boost/test/unit_test.hpp>
|
||||
|
||||
#include "formula/string_utils.hpp"
|
||||
#include "tstring.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
BOOST_AUTO_TEST_SUITE( formula_timespan )
|
||||
|
||||
using std::time_t;
|
||||
|
||||
namespace {
|
||||
|
||||
enum TIME_FACTORS
|
||||
{
|
||||
YEAR = 31104000, /* 12 months */
|
||||
MONTH = 2592000, /* 30 days */
|
||||
WEEK = 604800,
|
||||
DAY = 86400,
|
||||
HOUR = 3600,
|
||||
MIN = 60,
|
||||
SEC = 1,
|
||||
};
|
||||
|
||||
inline std::string minifmt(time_t t, const std::string& singular, const std::string& plural)
|
||||
{
|
||||
return t ? std::to_string(t) + " " + (t > 1 ? plural : singular) : "";
|
||||
}
|
||||
|
||||
typedef std::tuple<
|
||||
time_t /*sec*/,
|
||||
time_t /*min*/,
|
||||
time_t /*hr*/,
|
||||
time_t /*day*/,
|
||||
time_t /*wk*/,
|
||||
time_t /*mo*/,
|
||||
time_t /*yr*/> time_detailed;
|
||||
|
||||
inline time_t gen_as_time_t(const time_detailed& params)
|
||||
{
|
||||
time_t sec, min, hr, day, wk, mo, yr;
|
||||
std::tie(sec, min, hr, day, wk, mo, yr) = params;
|
||||
|
||||
return YEAR*yr + MONTH*mo + WEEK*wk + DAY*day + HOUR*hr + MIN*min + SEC*sec;
|
||||
}
|
||||
|
||||
inline std::string gen_as_str(const time_detailed& params)
|
||||
{
|
||||
time_t sec, min, hr, day, wk, mo, yr;
|
||||
std::tie(sec, min, hr, day, wk, mo, yr) = params;
|
||||
|
||||
std::vector<t_string> bits;
|
||||
std::string res;
|
||||
|
||||
bits.emplace_back(minifmt(yr, "year", "years"));
|
||||
bits.emplace_back(minifmt(mo, "month", "months"));
|
||||
bits.emplace_back(minifmt(wk, "week", "weeks"));
|
||||
bits.emplace_back(minifmt(day, "day", "days"));
|
||||
bits.emplace_back(minifmt(hr, "hour", "hours"));
|
||||
bits.emplace_back(minifmt(min, "minute", "minutes"));
|
||||
bits.emplace_back(minifmt(sec, "second", "seconds"));
|
||||
|
||||
// Drop zeroes
|
||||
auto p = std::remove_if(bits.begin(), bits.end(), [](const t_string& t) { return t.empty(); });
|
||||
if(p != bits.end()) {
|
||||
bits.erase(p);
|
||||
}
|
||||
|
||||
return utils::format_conjunct_list("expired", bits);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE( test_formula_timespan )
|
||||
{
|
||||
time_detailed t;
|
||||
|
||||
t = { 1, 0, 0, 0, 0, 0, 0 };
|
||||
BOOST_CHECK_EQUAL("1 second", utils::format_timespan(gen_as_time_t(t)));
|
||||
|
||||
t = { 2, 0, 0, 0, 0, 0, 0 };
|
||||
BOOST_CHECK_EQUAL("2 seconds", utils::format_timespan(gen_as_time_t(t)));
|
||||
|
||||
t = { 0, 1, 0, 0, 0, 0, 0 };
|
||||
BOOST_CHECK_EQUAL("1 minute", utils::format_timespan(gen_as_time_t(t)));
|
||||
|
||||
t = { 0, 2, 0, 0, 0, 0, 0 };
|
||||
BOOST_CHECK_EQUAL("2 minutes", utils::format_timespan(gen_as_time_t(t)));
|
||||
|
||||
t = { 0, 0, 1, 0, 0, 0, 0 };
|
||||
BOOST_CHECK_EQUAL("1 hour", utils::format_timespan(gen_as_time_t(t)));
|
||||
|
||||
t = { 0, 0, 2, 0, 0, 0, 0 };
|
||||
BOOST_CHECK_EQUAL("2 hours", utils::format_timespan(gen_as_time_t(t)));
|
||||
|
||||
t = { 0, 0, 0, 1, 0, 0, 0 };
|
||||
BOOST_CHECK_EQUAL("1 day", utils::format_timespan(gen_as_time_t(t)));
|
||||
|
||||
t = { 0, 0, 0, 2, 0, 0, 0 };
|
||||
BOOST_CHECK_EQUAL("2 days", utils::format_timespan(gen_as_time_t(t)));
|
||||
|
||||
t = { 0, 0, 0, 0, 1, 0, 0 };
|
||||
BOOST_CHECK_EQUAL("1 week", utils::format_timespan(gen_as_time_t(t)));
|
||||
|
||||
t = { 0, 0, 0, 0, 2, 0, 0 };
|
||||
BOOST_CHECK_EQUAL("2 weeks", utils::format_timespan(gen_as_time_t(t)));
|
||||
|
||||
t = { 0, 0, 0, 0, 0, 1, 0 };
|
||||
BOOST_CHECK_EQUAL("1 month", utils::format_timespan(gen_as_time_t(t)));
|
||||
|
||||
t = { 0, 0, 0, 0, 0, 2, 0 };
|
||||
BOOST_CHECK_EQUAL("2 months", utils::format_timespan(gen_as_time_t(t)));
|
||||
|
||||
t = { 0, 0, 0, 0, 0, 0, 1 };
|
||||
BOOST_CHECK_EQUAL("1 year", utils::format_timespan(gen_as_time_t(t)));
|
||||
|
||||
t = { 0, 0, 0, 0, 0, 0, 2 };
|
||||
BOOST_CHECK_EQUAL("2 years", utils::format_timespan(gen_as_time_t(t)));
|
||||
|
||||
t = { 12, 1, 23, 3, 2, 5, 2 };
|
||||
BOOST_CHECK_EQUAL(gen_as_str(t), utils::format_timespan(gen_as_time_t(t)));
|
||||
|
||||
t = { 0, 0, 0, 0, 0, 0, 0 };
|
||||
BOOST_CHECK_EQUAL(utils::format_timespan(gen_as_time_t(t)), utils::format_timespan(0));
|
||||
BOOST_CHECK_EQUAL(utils::format_timespan(gen_as_time_t(t)), utils::format_timespan(-10000));
|
||||
|
||||
t = { 4, 0, 49, 0, 0, 0, 0 };
|
||||
BOOST_CHECK_EQUAL("2 days, 1 hour, and 4 seconds", utils::format_timespan(gen_as_time_t(t)));
|
||||
|
||||
t = { 0, 40, 0, 11, 1, 0, 4 };
|
||||
BOOST_CHECK_EQUAL("4 years, 2 weeks, 4 days, and 40 minutes", utils::format_timespan(gen_as_time_t(t)));
|
||||
|
||||
t = { 0, 0, 1, 0, 0, 3, 4 };
|
||||
BOOST_CHECK_EQUAL("4 years, 3 months, and 1 hour", utils::format_timespan(gen_as_time_t(t)));
|
||||
|
||||
t = { 10, 0, 0, 0, 0, 2, 0 };
|
||||
BOOST_CHECK_EQUAL("2 months and 10 seconds", utils::format_timespan(gen_as_time_t(t)));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_SUITE_END()
|
Loading…
Add table
Reference in a new issue