Merge pull request #4940 from beyertom/clock/configurable-week-numbering

clock: add weeks-numbering option for configurable CW calculation
This commit is contained in:
Alexis Rouillard
2026-07-04 00:56:29 +02:00
committed by GitHub
3 changed files with 40 additions and 8 deletions
+2
View File
@@ -12,6 +12,7 @@ const std::string kOrdPlaceholder{"ordinal_date"};
enum class CldMode { MONTH, YEAR }; enum class CldMode { MONTH, YEAR };
enum class WS { LEFT, RIGHT, HIDDEN }; enum class WS { LEFT, RIGHT, HIDDEN };
enum class WeekNumbering { LOCALE, ISO, MONDAY, SUNDAY };
class Clock final : public ALabel { class Clock final : public ALabel {
public: public:
@@ -51,6 +52,7 @@ class Clock final : public ALabel {
date::day cldBaseDay_{0}; // calendar Cached day. Is used when today is changing(midnight) date::day cldBaseDay_{0}; // calendar Cached day. Is used when today is changing(midnight)
std::string cldText_{""}; // calendar text to print std::string cldText_{""}; // calendar text to print
bool iso8601Calendar_{false}; // whether the calendar is in ISO8601 bool iso8601Calendar_{false}; // whether the calendar is in ISO8601
WeekNumbering weekNumbering_{WeekNumbering::LOCALE}; // week number calculation method
CldMode cldMode_{CldMode::MONTH}; CldMode cldMode_{CldMode::MONTH};
auto get_calendar(const date::year_month_day& today, const date::year_month_day& ymd, auto get_calendar(const date::year_month_day& today, const date::year_month_day& ymd,
const date::time_zone* tz) -> const std::string; const date::time_zone* tz) -> const std::string;
+10 -2
View File
@@ -138,6 +138,13 @@ View all valid format options in *strftime(3)* or have a look https://en.cpprefe
:[ When enabled, the calendar follows the ISO 8601 standard: weeks begin on :[ When enabled, the calendar follows the ISO 8601 standard: weeks begin on
Monday, and the first week of the year is numbered 1. The default week format is Monday, and the first week of the year is numbered 1. The default week format is
'{:%V}'. '{:%V}'.
|[ *weeks-numbering*
:[ string
:[
:[ Override the week number calculation method, independent of *iso8601* and
locale settings. Possible values: *iso* (ISO 8601, {:%V}), *monday*
(Monday-based, {:%W}), *sunday* (Sunday-based, {:%U}). When not set, the
method is derived from *iso8601* or the locale.
|[ *first-day-of-week* |[ *first-day-of-week*
:[ integer :[ integer
:[ :[
@@ -160,8 +167,9 @@ View all valid format options in *strftime(3)* or have a look https://en.cpprefe
|[ *weeks* |[ *weeks*
:[ string :[ string
:[ *{:%U}* :[ *{:%U}*
:[ Format is applied to week numbers. When weekday format is not provided then :[ Format is applied to week numbers. The *{}* placeholder is replaced with the
is used default format: '{:%W}' when week starts with Monday, '{:%U}' otherwise format determined by *weeks-numbering* (if set), otherwise by *iso8601* or the
locale: '{:%V}' for ISO 8601, '{:%W}' when week starts with Monday, '{:%U}' otherwise
|[ *weekdays* |[ *weekdays*
:[ string :[ string
:[ :[
+28 -6
View File
@@ -82,6 +82,20 @@ waybar::modules::Clock::Clock(const std::string& id, const Json::Value& config)
iso8601Calendar_ = config_[kCldPlaceholder]["iso8601"].asBool(); iso8601Calendar_ = config_[kCldPlaceholder]["iso8601"].asBool();
} }
if (config_[kCldPlaceholder]["weeks-numbering"].isString()) {
const std::string wn{config_[kCldPlaceholder]["weeks-numbering"].asString()};
const std::map<std::string, WeekNumbering> wnModes{{"iso", WeekNumbering::ISO},
{"monday", WeekNumbering::MONDAY},
{"sunday", WeekNumbering::SUNDAY}};
if (wnModes.find(wn) != wnModes.end())
weekNumbering_ = wnModes.at(wn);
else
spdlog::warn(
"Clock calendar configuration weeks-numbering \"{}\" is not recognized. "
"Locale default is used instead",
wn);
}
if (config_[kCldPlaceholder]["weeks-pos"].isString()) { if (config_[kCldPlaceholder]["weeks-pos"].isString()) {
if (config_[kCldPlaceholder]["weeks-pos"].asString() == "left") cldWPos_ = WS::LEFT; if (config_[kCldPlaceholder]["weeks-pos"].asString() == "left") cldWPos_ = WS::LEFT;
if (config_[kCldPlaceholder]["weeks-pos"].asString() == "right") cldWPos_ = WS::RIGHT; if (config_[kCldPlaceholder]["weeks-pos"].asString() == "right") cldWPos_ = WS::RIGHT;
@@ -105,18 +119,26 @@ waybar::modules::Clock::Clock(const std::string& id, const Json::Value& config)
cldBaseDay_ = year_month_day{floor<days>(local_time)}.day(); cldBaseDay_ = year_month_day{floor<days>(local_time)}.day();
} else } else
fmtMap_.insert({3, "{}"}); fmtMap_.insert({3, "{}"});
const auto weekFmt = [this]() -> std::string {
switch (weekNumbering_) {
case WeekNumbering::ISO:
return "{:%V}";
case WeekNumbering::MONDAY:
return "{:%W}";
case WeekNumbering::SUNDAY:
return "{:%U}";
default:
return iso8601Calendar_ ? "{:%V}" : ((first_day_of_week() == Monday) ? "{:%W}" : "{:%U}");
}
}();
if (config_[kCldPlaceholder]["format"]["weeks"].isString() && cldWPos_ != WS::HIDDEN) { if (config_[kCldPlaceholder]["format"]["weeks"].isString() && cldWPos_ != WS::HIDDEN) {
const auto defaultFmt =
iso8601Calendar_ ? "{:%V}" : ((first_day_of_week() == Monday) ? "{:%W}" : "{:%U}");
fmtMap_.insert({4, std::regex_replace(config_[kCldPlaceholder]["format"]["weeks"].asString(), fmtMap_.insert({4, std::regex_replace(config_[kCldPlaceholder]["format"]["weeks"].asString(),
std::regex("\\{\\}"), defaultFmt)}); std::regex("\\{\\}"), weekFmt)});
Glib::ustring tmp{std::regex_replace(fmtMap_[4], std::regex("</?[^>]+>|\\{.*\\}"), "")}; Glib::ustring tmp{std::regex_replace(fmtMap_[4], std::regex("</?[^>]+>|\\{.*\\}"), "")};
cldWnLen_ += tmp.size(); cldWnLen_ += tmp.size();
} else { } else {
if (cldWPos_ != WS::HIDDEN) { if (cldWPos_ != WS::HIDDEN) {
const auto defaultFmt = fmtMap_.insert({4, weekFmt});
iso8601Calendar_ ? "{:%V}" : ((first_day_of_week() == Monday) ? "{:%W}" : "{:%U}");
fmtMap_.insert({4, defaultFmt});
} else { } else {
cldWnLen_ = 0; cldWnLen_ = 0;
} }