time conversion between time zones

Signed-off-by: Viktar Lukashonak <myxabeer@gmail.com>
This commit is contained in:
Viktar Lukashonak 2023-07-24 01:21:30 +03:00
parent effad1a5c3
commit 4d9e0ea802
No known key found for this signature in database
GPG Key ID: 08A413AA87200A6F
2 changed files with 63 additions and 73 deletions

View File

@ -34,11 +34,18 @@ class Clock final : public ALabel {
auto first_day_of_week() -> date::weekday; auto first_day_of_week() -> date::weekday;
const date::time_zone* current_timezone(); const date::time_zone* current_timezone();
bool is_timezone_fixed(); auto timezones_text(std::chrono::system_clock::time_point now) -> std::string;
auto timezones_text(std::chrono::system_clock::time_point* now) -> std::string;
/*Calendar properties*/ /*Calendar properties*/
WeeksSide cldWPos_{WeeksSide::HIDDEN}; WeeksSide cldWPos_{WeeksSide::HIDDEN};
/*
0 - calendar.format.months
1 - calendar.format.weekdays
2 - calendar.format.days
3 - calendar.format.today
4 - calendar.format.weeks
5 - tooltip-format
*/
std::map<int, std::string const> fmtMap_; std::map<int, std::string const> fmtMap_;
CldMode cldMode_{CldMode::MONTH}; CldMode cldMode_{CldMode::MONTH};
uint cldMonCols_{3}; // Count of the month in the row uint cldMonCols_{3}; // Count of the month in the row
@ -52,8 +59,10 @@ class Clock final : public ALabel {
std::string cldMonCached_{}; std::string cldMonCached_{};
date::day cldBaseDay_{0}; date::day cldBaseDay_{0};
/*Calendar functions*/ /*Calendar functions*/
auto get_calendar(const date::zoned_seconds& now, const date::zoned_seconds& wtime) auto get_calendar(const date::year_month_day& today,
-> std::string; const date::year_month_day& ymd,
const date::time_zone* tz)
-> const std::string;
/*Clock actions*/ /*Clock actions*/
void cldModeSwitch(); void cldModeSwitch();
void cldShift_up(); void cldShift_up();

View File

@ -17,9 +17,9 @@
waybar::modules::Clock::Clock(const std::string& id, const Json::Value& config) waybar::modules::Clock::Clock(const std::string& id, const Json::Value& config)
: ALabel(config, "clock", id, "{:%H:%M}", 60, false, false, true), : ALabel(config, "clock", id, "{:%H:%M}", 60, false, false, true),
current_time_zone_idx_(0), current_time_zone_idx_{0},
is_calendar_in_tooltip_(false), is_calendar_in_tooltip_{false},
is_timezoned_list_in_tooltip_(false) { is_timezoned_list_in_tooltip_{false} {
if (config_["timezones"].isArray() && !config_["timezones"].empty()) { if (config_["timezones"].isArray() && !config_["timezones"].empty()) {
for (const auto& zone_name : config_["timezones"]) { for (const auto& zone_name : config_["timezones"]) {
if (!zone_name.isString()) continue; if (!zone_name.isString()) continue;
@ -35,8 +35,7 @@ waybar::modules::Clock::Clock(const std::string& id, const Json::Value& config)
} }
} else if (config_["timezone"].isString()) { } else if (config_["timezone"].isString()) {
if (config_["timezone"].asString().empty()) if (config_["timezone"].asString().empty())
// nullptr means that local time should be shown time_zones_.push_back(date::current_zone());
time_zones_.push_back(nullptr);
else else
try { try {
time_zones_.push_back(date::locate_zone(config_["timezone"].asString())); time_zones_.push_back(date::locate_zone(config_["timezone"].asString()));
@ -48,20 +47,22 @@ waybar::modules::Clock::Clock(const std::string& id, const Json::Value& config)
// If all timezones are parsed and no one is good // If all timezones are parsed and no one is good
if (!time_zones_.size()) { if (!time_zones_.size()) {
// nullptr means that local time should be shown // nullptr means that local time should be shown
time_zones_.push_back(nullptr); time_zones_.push_back(date::current_zone());
} }
// Check if a particular placeholder is present in the tooltip format, to know what to calculate // Check if a particular placeholder is present in the tooltip format, to know what to calculate
// on update. // on update.
if (config_["tooltip-format"].isString()) { if (config_["tooltip-format"].isString()) {
std::string trimmed_format = config_["tooltip-format"].asString(); std::string trimmed_format{config_["tooltip-format"].asString()};
trimmed_format.erase(std::remove_if(trimmed_format.begin(), trimmed_format.end(), trimmed_format.erase(std::remove_if(trimmed_format.begin(), trimmed_format.end(),
[](unsigned char x) { return std::isspace(x); }), [](unsigned char x) { return std::isspace(x); }),
trimmed_format.end()); trimmed_format.end());
if (trimmed_format.find("{" + kCalendarPlaceholder + "}") != std::string::npos) { fmtMap_.insert({5, trimmed_format});
if (fmtMap_[5].find("{" + kCalendarPlaceholder + "}") != std::string::npos) {
is_calendar_in_tooltip_ = true; is_calendar_in_tooltip_ = true;
} }
if (trimmed_format.find("{" + KTimezonedTimeListPlaceholder + "}") != std::string::npos) { if (fmtMap_[5].find("{" + KTimezonedTimeListPlaceholder + "}") != std::string::npos) {
is_timezoned_list_in_tooltip_ = true; is_timezoned_list_in_tooltip_ = true;
} }
} }
@ -158,52 +159,33 @@ waybar::modules::Clock::Clock(const std::string& id, const Json::Value& config)
} }
const date::time_zone* waybar::modules::Clock::current_timezone() { const date::time_zone* waybar::modules::Clock::current_timezone() {
return is_timezone_fixed() ? time_zones_[current_time_zone_idx_] : date::current_zone(); return time_zones_[current_time_zone_idx_];
}
bool waybar::modules::Clock::is_timezone_fixed() {
return time_zones_[current_time_zone_idx_] != nullptr;
} }
auto waybar::modules::Clock::update() -> void { auto waybar::modules::Clock::update() -> void {
const auto* time_zone = current_timezone(); const auto* tz{current_timezone()};
auto now = std::chrono::system_clock::now(); const date::zoned_time now{
auto ztime = date::zoned_time{time_zone, date::floor<std::chrono::seconds>(now)}; tz, std::chrono::system_clock::now()}; // Define local time is based on provided time zone
const date::year_month_day today{
date::floor<date::days>(now.get_local_time())}; // Convert now to year_month_day
const date::year_month_day shiftedDay{today + cldCurrShift_}; // Shift today
// Define shift local time
const auto shiftedNow{date::make_zoned(
tz, date::local_days(shiftedDay) +
(now.get_local_time() - date::floor<date::days>(now.get_local_time())))};
auto shifted_date = date::year_month_day{date::floor<date::days>(now)} + cldCurrShift_; label_.set_markup(fmt::format(locale_, fmt::runtime(format_), now));
if (cldCurrShift_.count()) {
shifted_date = date::year_month_day(shifted_date.year(), shifted_date.month(), date::day(1));
}
auto now_shifted = date::sys_days{shifted_date} + (now - date::floor<date::days>(now));
auto shifted_ztime = date::zoned_time{time_zone, date::floor<std::chrono::seconds>(now_shifted)};
std::string text{""};
if (!is_timezone_fixed()) {
// As date dep is not fully compatible, prefer fmt
tzset();
auto localtime = fmt::localtime(std::chrono::system_clock::to_time_t(now));
text = fmt::format(locale_, fmt::runtime(format_), localtime);
} else {
text = fmt::format(locale_, fmt::runtime(format_), ztime);
}
label_.set_markup(text);
if (tooltipEnabled()) { if (tooltipEnabled()) {
if (config_["tooltip-format"].isString()) { const std::string tz_text{(is_timezoned_list_in_tooltip_) ? timezones_text(now.get_sys_time())
std::string calendar_lines{""}; : ""};
std::string timezoned_time_lines{""}; const std::string cld_text{(is_calendar_in_tooltip_) ? get_calendar(today, shiftedDay, tz)
if (is_calendar_in_tooltip_) { : ""};
calendar_lines = get_calendar(ztime, shifted_ztime);
} const std::string text{fmt::format(locale_, fmt::runtime(fmtMap_[5]), shiftedNow,
if (is_timezoned_list_in_tooltip_) { fmt::arg(KTimezonedTimeListPlaceholder.c_str(), tz_text),
timezoned_time_lines = timezones_text(&now); fmt::arg(kCalendarPlaceholder.c_str(), cld_text))};
} label_.set_tooltip_markup(text);
auto tooltip_format = config_["tooltip-format"].asString();
text = fmt::format(locale_, fmt::runtime(tooltip_format), shifted_ztime,
fmt::arg(kCalendarPlaceholder.c_str(), calendar_lines),
fmt::arg(KTimezonedTimeListPlaceholder.c_str(), timezoned_time_lines));
label_.set_tooltip_markup(text);
}
} }
// Call parent update // Call parent update
@ -219,15 +201,15 @@ auto waybar::modules::Clock::doAction(const std::string& name) -> void {
} }
// The number of weeks in calendar month layout plus 1 more for calendar titles // The number of weeks in calendar month layout plus 1 more for calendar titles
unsigned cldRowsInMonth(date::year_month const ym, date::weekday const firstdow) { const unsigned cldRowsInMonth(const date::year_month& ym, const date::weekday& firstdow) {
using namespace date; using namespace date;
return static_cast<unsigned>( return static_cast<unsigned>(
ceil<weeks>((weekday{ym / 1} - firstdow) + ((ym / last).day() - day{0})).count()) + ceil<weeks>((weekday{ym / 1} - firstdow) + ((ym / last).day() - day{0})).count()) +
2; 2;
} }
auto cldGetWeekForLine(date::year_month const ym, date::weekday const firstdow, unsigned const line) auto cldGetWeekForLine(const date::year_month& ym, const date::weekday& firstdow,
-> const date::year_month_weekday { unsigned const line) -> const date::year_month_weekday {
unsigned index = line - 2; unsigned index = line - 2;
auto sd = date::sys_days{ym / 1}; auto sd = date::sys_days{ym / 1};
if (date::weekday{sd} == firstdow) ++index; if (date::weekday{sd} == firstdow) ++index;
@ -235,8 +217,8 @@ auto cldGetWeekForLine(date::year_month const ym, date::weekday const firstdow,
return ymdw; return ymdw;
} }
auto getCalendarLine(date::year_month_day const currDate, date::year_month const ym, auto getCalendarLine(const date::year_month_day& currDate, const date::year_month ym,
unsigned const line, date::weekday const firstdow, const unsigned line, const date::weekday& firstdow,
const std::locale* const locale_) -> std::string { const std::locale* const locale_) -> std::string {
using namespace date::literals; using namespace date::literals;
std::ostringstream res; std::ostringstream res;
@ -318,10 +300,9 @@ auto getCalendarLine(date::year_month_day const currDate, date::year_month const
return res.str(); return res.str();
} }
auto waybar::modules::Clock::get_calendar(const date::zoned_seconds& now, auto waybar::modules::Clock::get_calendar(const date::year_month_day& today,
const date::zoned_seconds& wtime) -> std::string { const date::year_month_day& ymd,
auto daypoint = date::floor<date::days>(wtime.get_local_time()); const date::time_zone* tz) -> const std::string {
const auto ymd{date::year_month_day{daypoint}};
const auto ym{ymd.year() / ymd.month()}; const auto ym{ymd.year() / ymd.month()};
const auto y{ymd.year()}; const auto y{ymd.year()};
const auto d{ymd.day()}; const auto d{ymd.day()};
@ -329,9 +310,6 @@ auto waybar::modules::Clock::get_calendar(const date::zoned_seconds& now,
const auto maxRows{12 / cldMonCols_}; const auto maxRows{12 / cldMonCols_};
std::ostringstream os; std::ostringstream os;
std::ostringstream tmp; std::ostringstream tmp;
// get currdate
daypoint = date::floor<date::days>(now.get_local_time());
const auto currDate{date::year_month_day{daypoint}};
if (cldMode_ == CldMode::YEAR) { if (cldMode_ == CldMode::YEAR) {
if (y / date::month{1} / 1 == cldYearShift_) if (y / date::month{1} / 1 == cldYearShift_)
@ -361,6 +339,7 @@ auto waybar::modules::Clock::get_calendar(const date::zoned_seconds& now,
else else
m = 0u; m = 0u;
} }
for (auto row{0u}; row < maxRows; ++row) { for (auto row{0u}; row < maxRows; ++row) {
const auto lines = *std::max_element(std::begin(ml) + (row * cldMonCols_), const auto lines = *std::max_element(std::begin(ml) + (row * cldMonCols_),
std::begin(ml) + ((row + 1) * cldMonCols_)); std::begin(ml) + ((row + 1) * cldMonCols_));
@ -377,8 +356,9 @@ auto waybar::modules::Clock::get_calendar(const date::zoned_seconds& now,
if (line < ml[static_cast<unsigned>(ymTmp.month()) - 1u]) if (line < ml[static_cast<unsigned>(ymTmp.month()) - 1u])
os << fmt::format(fmt::runtime(fmtMap_[4]), os << fmt::format(fmt::runtime(fmtMap_[4]),
(line == 2) (line == 2)
? date::sys_days{ymTmp / 1} ? date::zoned_seconds{tz, date::local_days{ymTmp / 1}}
: date::sys_days{cldGetWeekForLine(ymTmp, firstdow, line)}) : date::zoned_seconds{tz, date::local_days{cldGetWeekForLine(
ymTmp, firstdow, line)}})
<< ' '; << ' ';
else else
os << std::string(cldWnLen_, ' '); os << std::string(cldWnLen_, ' ');
@ -387,7 +367,7 @@ auto waybar::modules::Clock::get_calendar(const date::zoned_seconds& now,
os << fmt::format( os << fmt::format(
fmt::runtime((cldWPos_ != WeeksSide::LEFT || line == 0) ? "{:<{}}" : "{:>{}}"), fmt::runtime((cldWPos_ != WeeksSide::LEFT || line == 0) ? "{:<{}}" : "{:>{}}"),
getCalendarLine(currDate, ymTmp, line, firstdow, &locale_), getCalendarLine(today, ymTmp, line, firstdow, &locale_),
(cldMonColLen_ + ((line < 2) ? cldWnLen_ : 0))); (cldMonColLen_ + ((line < 2) ? cldWnLen_ : 0)));
// Week numbers on the right // Week numbers on the right
@ -397,8 +377,9 @@ auto waybar::modules::Clock::get_calendar(const date::zoned_seconds& now,
os << ' ' os << ' '
<< fmt::format(fmt::runtime(fmtMap_[4]), << fmt::format(fmt::runtime(fmtMap_[4]),
(line == 2) (line == 2)
? date::sys_days{ymTmp / 1} ? date::zoned_seconds{tz, date::local_days{ymTmp / 1}}
: date::sys_days{cldGetWeekForLine(ymTmp, firstdow, line)}); : date::zoned_seconds{tz, date::local_days{cldGetWeekForLine(
ymTmp, firstdow, line)}});
else else
os << std::string(cldWnLen_, ' '); os << std::string(cldWnLen_, ' ');
} }
@ -421,7 +402,7 @@ auto waybar::modules::Clock::get_calendar(const date::zoned_seconds& now,
os << fmt::format( // Apply days format os << fmt::format( // Apply days format
fmt::runtime(fmt::format(fmt::runtime(fmtMap_[2]), tmp.str())), fmt::runtime(fmt::format(fmt::runtime(fmtMap_[2]), tmp.str())),
// Apply today format // Apply today format
fmt::arg("today", fmt::format(fmt::runtime(fmtMap_[3]), date::format("%e", ymd.day())))); fmt::arg("today", fmt::format(fmt::runtime(fmtMap_[3]), date::format("%e", d))));
if (cldMode_ == CldMode::YEAR) if (cldMode_ == CldMode::YEAR)
cldYearCached_ = os.str(); cldYearCached_ = os.str();
@ -457,7 +438,7 @@ void waybar::modules::Clock::tz_down() {
current_time_zone_idx_ = current_time_zone_idx_ == 0 ? nr_zones - 1 : current_time_zone_idx_ - 1; current_time_zone_idx_ = current_time_zone_idx_ == 0 ? nr_zones - 1 : current_time_zone_idx_ - 1;
} }
auto waybar::modules::Clock::timezones_text(std::chrono::system_clock::time_point* now) auto waybar::modules::Clock::timezones_text(std::chrono::system_clock::time_point now)
-> std::string { -> std::string {
if (time_zones_.size() == 1) { if (time_zones_.size() == 1) {
return ""; return "";
@ -471,7 +452,7 @@ auto waybar::modules::Clock::timezones_text(std::chrono::system_clock::time_poin
if (!timezone) { if (!timezone) {
timezone = date::current_zone(); timezone = date::current_zone();
} }
auto ztime = date::zoned_time{timezone, date::floor<std::chrono::seconds>(*now)}; auto ztime = date::zoned_time{timezone, date::floor<std::chrono::seconds>(now)};
os << fmt::format(locale_, fmt::runtime(format_), ztime) << '\n'; os << fmt::format(locale_, fmt::runtime(format_), ztime) << '\n';
} }
return os.str(); return os.str();