使用C ++ 20<chrono>

问题描述 投票:0回答:1

我知道我可以通过基于ISO周的日历(

%G
%V
%u
)格式化计时日期,但是我如何使用
<chrono>

来计算这些值
c++ c++20 c++-chrono
1个回答
6
投票

我建议创建一种类型,该类型持有基于ISO周的年度,周数和工作日,并提供该类型的转换功能往返

std::chrono::sys_days
。 这为您提供了所需的内容(转换为基于ISO周的日历)和基于ISO周的日历。 它使您与任何其他具有往返于sys_days的转换的日历系统互操作。 此数据结构的初稿可能看起来像:
struct iso_week_date
{
    std::int16_t year;
    std::uint8_t weeknum;
    std::chrono::weekday dow;

    constexpr iso_week_date(int y, unsigned wn, std::chrono::weekday wd) noexcept : year{ y }, weeknum{ wn }, dow{ wd } {}
    constexpr iso_week_date(std::chrono::sys_days tp) noexcept;
    constexpr operator std::chrono::sys_days() const noexcept;
};
为了示范目的,我尽可能简单。 人们可以轻松地看到一个人可以在此添加功能,例如年度算术,使数据成员私密,并给予他们获取器和固定器,添加流和解析操作员等。

采用A的构造函数是问题中要求的转换函数。

sys_days

是反向转换。 这些可以在这些操作的汇编计算上进行
operator sys_days

noexcept

constexpr

启用编译时间计算。
llet从
sys_days
构造器开始:
关于基于ISO周的日历,首先要了解的是,它将一年分为52或53周,周一开始。  每个星期都在一年的ISO年内完全。  因此,ISO年并不总是与民事年份相同,尽管通常是。  在民事年份的开始或结束时,ISO年可能是公民年份的一个。  例如,当12月31日落在星期一时,该星期一的股票与下周四的同年相同,比周一大的年度大。
对于星期四以外的每一天,民事年份可能比ISO年前落后一个或一个。 但是在星期四,民事年度和ISO年总是相同的。 结合一个星期(星期一至周日)始终在同一年中,这对于计算从
sys_days

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 std::chrono::sys_days;
    using std::chrono::year_month_day;
    using std::chrono::Monday;
    using std::chrono::Thursday;
    using std::chrono::weeks;
    using std::chrono::weekday;
    using std::chrono::days;
    using std::chrono::floor;

    dow = weekday{tp};
    auto closest_thursday = [this](sys_days tp)
    {
        auto i = static_cast<int>(dow.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;
}

辅助功能将其绘制为

closest_thursday

,并将其映射到最近的星期四。 也就是说,它增加了几天到星期一,星期二或星期三,并从星期五,周六或周日减去几天,以便制作星期四。 这用于获得ISO周的正确ISO年份,无论一周中的哪一天,

sys_days

都指的是。
一旦计算正确的ISO年,ISO年的开始是一年中第一个星期四之前的星期一。  这一表达只是一种详细的写作方式,旨在表明该表达在第一个星期四之前的星期一找到。  如果需要,请替换。  这不会影响代码的正确性或性能。
填写剩余的
tp
数据成员是直接的。 请注意,一周的数量从1开始,而不是0,因此

tp
反向转换(从

(Thursday - Monday)

days{3}
)甚至更容易:
days{3}
ISO年开始计算(第一个星期四之前的星期一)。然后添加正确的几周数和星期一之后的天数。 this可以这样行使这一点:
iso_week_date

这将A

+ 1
转换为
iso_week_date
。 请注意,代码中的任何地方都没有意识到类型。 然后将A
sys_days
转换为

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); }

。 这恰好与上一个示例相同。 并请注意,

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

(朱利安,希伯来语,玛雅,伊斯兰,基于周的日历的日历...)的日历,也将也能够转换为这些日历。
最终使用反向转换来查找3天后的日期。
输出:

iso_week_date

demo.


最新问题
© www.soinside.com 2019 - 2025. All rights reserved.