clock: add weeks-numbering option for configurable CW calculation

The iso8601 flag previously controlled both the calendar grid layout
and the week number format as a coupled boolean. This adds a new
weeks-numbering option (iso/monday/sunday) that explicitly overrides
just the week number calculation method, independent of iso8601 and
locale settings. Existing behaviour is fully preserved when the option
is not set.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Thomas Beyer
2026-03-20 11:43:17 +01:00
co-authored by Claude Sonnet 4.6
parent ab7bfdb297
commit 86d516c74d
3 changed files with 42 additions and 9 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.
3. Addressed by *clock: calendar: format* 3. Addressed by *clock: calendar: format*
[- *Option* [- *Option*
@@ -155,8 +162,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
:[ :[
+29 -6
View File
@@ -81,6 +81,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;
@@ -104,18 +118,27 @@ 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;
} }