我知道我可以用基于ISO周的日历(%G,%V和%u)格式化计时日期,但我如何使用<chrono>自己计算这些值?
%G
%V
%u
<chrono>
dsekswqp1#
我建议创建一个类型来保存基于ISO周的年、周数和工作日,并为该类型提供std::chrono::sys_days和std::chrono::sys_days之间的转换函数。这可以满足您的要求(转换为基于ISO周的日历)* 和**从 * 基于ISO周的日历。它可以让您与任何其他具有sys_days和sys_days之间转换的日历系统进行互操作。此数据结构的初稿可能如下所示:
std::chrono::sys_days
sys_days
struct iso_week_date { std::int32_t year; std::uint8_t weeknum; std::chrono::weekday dow; constexpr iso_week_date(int y, unsigned wn, std::chrono::weekday wd) noexcept; constexpr iso_week_date(std::chrono::sys_days tp) noexcept; constexpr operator std::chrono::sys_days() const noexcept; };
字符串为了演示的目的,我已经尽可能的简单了,你可以很容易地看到,你可以添加一些功能,比如年份算法,使数据成员私有化,给它们给予getter和setter,添加流和解析操作符,等等。接受sys_days的构造函数是问题中要求的转换函数。operator sys_days是反向转换。这些可以简单地变成noexcept和constexpr,从而实现这些操作的编译时计算。让我们从sys_days构造函数开始:首先要了解的是ISO基于周的日历是,它将一年分为52或53周,周从星期一开始。每周都完全在ISO年的一年内。因此ISO年并不总是与民用年相同,尽管通常是。在民用年的开始或结束附近,ISO年份可以是民用年份之一。例如,当12月31日福尔斯落在星期一时,该星期一与下一个星期四共享同一年,比该星期一的民用年份大一。除了星期四,一周中的每一天的民用年都可以比ISO年份晚一年或早一年。但是对于星期四,民用年和ISO年份总是相同的。结合一周(星期一到星期日)总是在同一年的事实,在计算从sys_days到iso_week_date的转换时很重要。
operator sys_days
noexcept
constexpr
iso_week_date
constexpr iso_week_date::iso_week_date(std::chrono::sys_days tp) noexcept : iso_week_date{0, 0, std::chrono::weekday{}} { using namespace std::chrono; auto closest_thursday = [](sys_days tp) { weekday wd{tp}; auto i = static_cast<int>(wd.iso_encoding()); tp += days{4-i}; return tp; }; auto y = year_month_day{closest_thursday(tp)}.year(); auto start = sys_days{y/1/Thursday[1]} - (Thursday - Monday); year = int{y}; weeknum = floor<weeks>(tp - start) / weeks{1} + 1; dow = weekday{tp}; }
型closest_thursday辅助函数获取sys_days并将其Map到最近的星期四。也就是说,它将星期一,星期二或星期三添加几天,并从星期五,星期六或星期日减去几天以产生星期四。这用于为tp引用的ISO周获取正确的ISO年份,无论tp是星期几。一旦计算出正确的ISO年份,ISO年份的开始是该年第一个星期四之前的星期一。表达式(Thursday - Monday)只是days{3}的一种详细写法,旨在表明表达式正在查找第一个星期四之前的星期一。如果需要,可以替换days{3}。这不会影响代码的正确性或性能。接下来,直接填写iso_week_date数据成员。注意,周计数从1开始,而不是0,因此+ 1。反向转换(从iso_week_date到sys_days)更容易:
closest_thursday
tp
(Thursday - Monday)
days{3}
+ 1
constexpr iso_week_date::operator std::chrono::sys_days() const noexcept { using std::chrono::sys_days; using std::chrono::Monday; using std::chrono::Thursday; using std::chrono::weeks; auto start = sys_days{std::chrono::year{year}/1/Thursday[1]} - (Thursday - Monday); return start + weeks{weeknum-1} + (dow - Monday); }
型首先计算ISO年份的开始(第一个星期四之前的星期一),然后加上正确的周数和星期一之后的天数。这可以像这样练习:
int main() { using namespace std::chrono; iso_week_date d1{2024y/March/29}; std::cout << d1.year << "-W" << unsigned{d1.weeknum} << " " << d1.dow << '\n'; iso_week_date d2{Friday[last]/March/2024}; std::cout << d2.year << "-W" << unsigned{d2.weeknum} << " " << d2.dow << '\n'; sys_days d3 = sys_days{d2} + days{3}; std::cout << d3 << '\n'; }
型这将year_month_day转换为iso_week_date。请注意,代码中没有任何地方是iso_week_date知道类型year_month_day。然后它将year_weekday_last转换为iso_week_date。这恰好与前面的示例相同。请注意,iso_week_date不知道类型year_weekday_last。转换是从year_weekday_last反弹的。sys_days引擎盖下。请注意,如果其他人创建了另一个具有与sys_days(朱利安,希伯来语,玛雅语,伊斯兰教等)之间转换的日历,那么iso_week_date也将能够与这些日历进行转换。最后用逆转换求出3天后的日期。输出量:
year_month_day
year_weekday_last
2024-W13 Fri 2024-W13 Fri 2024-04-01
型Demo.
1条答案
按热度按时间dsekswqp1#
我建议创建一个类型来保存基于ISO周的年、周数和工作日,并为该类型提供
std::chrono::sys_days
和std::chrono::sys_days
之间的转换函数。这可以满足您的要求(转换为基于ISO周的日历)* 和**从 * 基于ISO周的日历。它可以让您与任何其他具有sys_days
和sys_days
之间转换的日历系统进行互操作。此数据结构的初稿可能如下所示:
字符串
为了演示的目的,我已经尽可能的简单了,你可以很容易地看到,你可以添加一些功能,比如年份算法,使数据成员私有化,给它们给予getter和setter,添加流和解析操作符,等等。
接受
sys_days
的构造函数是问题中要求的转换函数。operator sys_days
是反向转换。这些可以简单地变成noexcept
和constexpr
,从而实现这些操作的编译时计算。让我们从
sys_days
构造函数开始:首先要了解的是ISO基于周的日历是,它将一年分为52或53周,周从星期一开始。每周都完全在ISO年的一年内。因此ISO年并不总是与民用年相同,尽管通常是。在民用年的开始或结束附近,ISO年份可以是民用年份之一。例如,当12月31日福尔斯落在星期一时,该星期一与下一个星期四共享同一年,比该星期一的民用年份大一。
除了星期四,一周中的每一天的民用年都可以比ISO年份晚一年或早一年。但是对于星期四,民用年和ISO年份总是相同的。结合一周(星期一到星期日)总是在同一年的事实,在计算从
sys_days
到iso_week_date
的转换时很重要。型
closest_thursday
辅助函数获取sys_days
并将其Map到最近的星期四。也就是说,它将星期一,星期二或星期三添加几天,并从星期五,星期六或星期日减去几天以产生星期四。这用于为tp
引用的ISO周获取正确的ISO年份,无论tp
是星期几。一旦计算出正确的ISO年份,ISO年份的开始是该年第一个星期四之前的星期一。表达式
(Thursday - Monday)
只是days{3}
的一种详细写法,旨在表明表达式正在查找第一个星期四之前的星期一。如果需要,可以替换days{3}
。这不会影响代码的正确性或性能。接下来,直接填写
iso_week_date
数据成员。注意,周计数从1开始,而不是0,因此+ 1
。反向转换(从
iso_week_date
到sys_days
)更容易:型
首先计算ISO年份的开始(第一个星期四之前的星期一),然后加上正确的周数和星期一之后的天数。
这可以像这样练习:
型
这将
year_month_day
转换为iso_week_date
。请注意,代码中没有任何地方是iso_week_date
知道类型year_month_day
。然后它将year_weekday_last
转换为iso_week_date
。这恰好与前面的示例相同。请注意,iso_week_date
不知道类型year_weekday_last
。转换是从year_weekday_last
反弹的。sys_days
引擎盖下。请注意,如果其他人创建了另一个具有与
sys_days
(朱利安,希伯来语,玛雅语,伊斯兰教等)之间转换的日历,那么iso_week_date
也将能够与这些日历进行转换。最后用逆转换求出3天后的日期。
输出量:
型
Demo.